You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1072 lines
39 KiB
Python

# our magic factory makes game items and objects for us.
# methods prefixed with spawn_ are wrappers that return a random
# object within a certain genre. i.e. spawn_foliage could return
# a tree, a bush, a cactus...
import os
import copy
import random
import lib.libtcodpy as libtcod
import constants as C
import classes as cls
# define our tile characters here so we can do easy ascii to map lookups
CHAR_FENCE = "#"
CHAR_GRAVEL = ":"
CHAR_STONE = chr(176)
CHAR_WATER = "~"
CHAR_BRICK = chr(177)
CHAR_TOY = chr(13)
CHAR_FOOD = chr(3)
CHAR_TREE = chr(6)
CHAR_BUSH = chr(5)
CHAR_FLOWERS = chr(15)
def dice(sides):
return random.randint(0, sides) == 0
#===============================================================[[ Foliage ]]
def get_tree():
names = ('Tree', 'Oak Tree', 'Bark Tree', 'Big Tree')
colors = (libtcod.darkest_lime, libtcod.darkest_amber, libtcod.darkest_orange, libtcod.darkest_green)
fol = cls.ItemBase()
fol.char = CHAR_TREE
fol.name = random.choice(names)
fol.fgcolor = random.choice(colors)
fol.blocking = False
fol.seethrough = False
return fol
def get_bush():
names = ('Shrubbery', 'Thicket', 'Thornbush', 'Rosebush')
colors = (libtcod.darkest_chartreuse
, libtcod.darkest_green, libtcod.darkest_lime)
fol = cls.ItemBase()
fol.char = CHAR_BUSH
fol.name = random.choice(names)
fol.fgcolor = random.choice(colors)
fol.blocking = False
fol.fov_limit = random.randint(1, 3)
return fol
def get_flower():
names = ('Flowers', 'Roses')
colors = (libtcod.light_amber, libtcod.light_magenta
, libtcod.light_red, libtcod.light_azure, libtcod.light_yellow)
fol = cls.ItemBase()
fol.char = CHAR_FLOWERS
fol.name = random.choice(names)
# fol.bgcolor = libtcod.dark_green
fol.fgcolor = random.choice(colors)
fol.blocking = False
fol.fov_limit = random.randint(1, 3)
return fol
def spawn_foliage(currentmap, amount, thicket_size=4, density=10):
"""
spawn amount of random foliages, using currentmap to test against
overlapping locations. Take care not to spawn too many when the
map is full, this will enter an unbreakable loop.
adjust the <thicket_size> and <density> parameters accordingly.
"""
plant_choices = (get_tree
,get_bush
,get_flower
)
for loop in range(amount):
while True:
x = random.randint(0, C.MAP_WIDTH - thicket_size - 1)
y = random.randint(0, C.MAP_HEIGHT - thicket_size - 1)
if currentmap[x][y].isblank():
for thicket in range(density):
tx = x + random.randint(1, thicket_size)
ty = y +random.randint(1, thicket_size)
if currentmap[tx][ty].isblank():
currentmap[tx][ty] = random.choice(plant_choices)()
break
#=================================================================[[ Water ]]
def get_pool_tile():
colors = (libtcod.sky, libtcod.azure, libtcod.dark_cyan, libtcod.dark_azure)
puddle = cls.ItemBase()
puddle.drinkable = True
puddle.char = CHAR_WATER
puddle.name = "pool"
puddle.fgcolor = random.choice(colors)
puddle.bgcolor = libtcod.darker_sky
puddle.message = "*splash*"
return puddle
def spawn_pond(currentmap, amount, pond_size=4, density=6):
"""
Spawn a pond.
"""
for loop in range(amount):
while True:
x = random.randint(pond_size + 3, C.MAP_WIDTH - pond_size - 3)
y = random.randint(pond_size + 3, C.MAP_HEIGHT - pond_size - 3)
if density == 0:
# fill the entire range
x = x - pond_size
y = y - pond_size
for ty in range(pond_size):
for tx in range(pond_size):
tile = currentmap[x + tx][y + ty]
if tile.isblank():
wetness = get_pool_tile()
wetness.char = CHAR_WATER
wetness.fgcolor = POOL_FG
wetness.bgcolor = POOL_BG
wetness.name = "Pool"
currentmap[x + tx][y + ty] = wetness
break
else:
# spot fill the range
for litres in range(density):
tx = x + random.randint(1, pond_size)
ty = y +random.randint(1, pond_size)
if currentmap[tx][ty].isblank():
# transfer the current cell bgcolor
bgcolor = currentmap[tx][ty].bgcolor
puddle = get_pool_tile()
currentmap[tx][ty] = puddle
break
#=============================================================[[ Inventory ]]
def place_on_map(game_map, game_objects, item, near_xy=None):
"""
place item on a blank map tile. dont overlap existing objects either.
"""
tries = 0
radius = 4
while True:
tries = tries + 1
if tries % 10 == 0:
radius = radius + 1
if near_xy:
x = random.randint(near_xy[0] - radius, near_xy[0] + radius)
y = random.randint(near_xy[1] - radius, near_xy[1] + radius)
if x > C.MAP_WIDTH - 3:
x = C.MAP_WIDTH - 3
if y > C.MAP_HEIGHT - 3:
y = C.MAP_HEIGHT - 3
if x < 4:
x = 4
if y < 4:
y = 4
else:
x = random.randint(4, C.MAP_WIDTH - 4)
y = random.randint(4, C.MAP_HEIGHT - 4)
# test against blocked map tiles
try_again = game_map[x][y].blocking
# test against object collisions
if not try_again:
for obj in game_objects:
if obj.x == x and obj.y == y:
try_again = True
if game_map[x][y].isblank() and not try_again:
item.x, item.y = (x, y)
break
def get_toy():
"""
get a random toy artifact.
"""
toy_names = ("a tennis ball", "a bouncy ball", "a rubber bone", "a knotted rope"
,"a rubber chicken", "a rubber ducky", "a fluffy ball"
, "a dog tag", "a stick", "a food bowl", "a blanket", "a bouncy ball"
)
# toy_colors = (libtcod.light_green, libtcod.lighter_red
# , libtcod.lighter_blue, libtcod.lighter_yellow
# , libtcod.lighter_lime, libtcod.lighter_sea, libtcod.lighter_han
# , libtcod.lighter_violet, libtcod.lighter_fuchsia)
toy = cls.ItemBase()
toy.name = random.choice(toy_names)
toy.char = CHAR_FOOD
toy.fgcolor = libtcod.yellow
toy.carryable = True
return toy
def get_food():
"""
get a food stuff.
"""
names = ("a biscuit", "a cherry pie", "a bone", "a banana", "salami", "a peach", "a pizza slice")
eat = cls.ItemBase()
eat.name = random.choice(names)
eat.char = CHAR_FOOD
eat.fgcolor = libtcod.light_magenta
eat.carryable = True
eat.edible = True
return eat
#================================================================[[ Quests ]]
#def generate_quest(game_map, game_objects, default_attack_rating):
# """
# generate a quest and place it in game.
# """
# # use these variables in messages:
# # %a - for antagonist, ie the one to recover the item from
# # %b - for the berieved, who lost their precious toy
# # %i - for the item name in question
# quests = (
# "I have lost my %i!\nPlease help me..."
# ,"I played in the garden and\nnow my %i is missing.\nHelp me look?"
# ,"%a took my %i.\nCan you bring it back for me?"
# )
# thankyous = (
# "You found my %i,\nThank you!"
# ,"My %i!\nI hope %a was not\nmuch trouble.\nMy Hero!"
# ,"My Hero!\nI will always remember\nthis moment!"
# ,"Thank you TopDog!\nMy %i is safe again..."
# )
#
# # gen quest
# quest = cls.Quest()
# quest.reward_cmd = "player.hp = 100"
#
# # gen quest item
# item = get_toy()
# item.quest_id = quest.quest_id
#
# quest_text = random.choice(quests).replace("%i", item.name)
# quest.title = "find the %s" % (item.name)
# quest.thankyou = random.choice(thankyous).replace("%i", item.name)
# npc = None
#
# # give to a NPC, or place quest item on the map
## if random.randint(0, 1) == 0:
# if True:
# npc = get_random_npc(attack_rating=default_attack_rating)
# # set attack_rating if hostile, otherwise NPC hits with 0 damaage :p
# npc.action_ai.hostile = False
# if npc.action_ai.hostile:
# npc.move_ai.behaviour = random.choice((cls.MoveAI.HUNTING, cls.MoveAI.NEUTRAL))
# else:
# npc.move_ai.behaviour = cls.MoveAI.NEUTRAL
# quest_text = quest_text.replace("%a", npc.name)
# quest.thankyou = quest.thankyou.replace("%a", npc.name)
# npc.fgcolor = libtcod.pink
# # quest ai
# quest_ai = cls.QuestAI(npc)
# quest_ai.quest_id = quest.quest_id
# quest_ai.item = item
# # let the offender say something
## quest_ai.message = "here take it!" # antagonist dialogue message
# quest.owner = npc
# npc.quest_ai = quest_ai
# # done
# place_on_map(game_map, game_objects, npc)
# game_objects.append(npc)
# else:
# place_on_map(game_map, game_objects, item)
# game_objects.append(item)
# quest_text = quest_text.replace("%a", "some animal")
#
# # gen quest giver
# giver = get_random_npc()
# aai = cls.ActionAI(giver)
# aai.dialogue_text = quest_text
# aai.hostile = False
# aai.quest = quest
# giver.action_ai = aai
# giver.fgcolor = libtcod.yellow
# place_on_map(game_map, game_objects, giver)
# game_objects.append(giver)
def link_quest(game_map, game_objects
, title, quest_master, quest_item
, quest_npc=None, success_dialogue=None, success_command=None
):
"""
Link the given items together into a quest.
quest_master gives us the quest.
quest_npc keeps the item we must retrieve.
"""
# message placeholders
# %a - for antagonist, ie the one to recover the item from
# %b - for the berieved, who lost their precious toy
# %i - for the item name in question
# AI (master gives the quest, npc has the item)
ai_master = cls.QuestAI()
quest_master.quest_ai = ai_master
quest_item.quest_id = ai_master.quest_id
if quest_npc:
ai_npc = copy.deepcopy(ai_master)
ai_npc.owner = quest_npc
ai_npc.item = quest_item
quest_npc.quest_ai = ai_npc
title = title.replace("%npca", quest_npc.name)
title = title.replace("%npcb", quest_master.name)
title = title.replace("%item", quest_item.name)
else:
# no npc carries this item, its placed on the map.
ai_master.owner = quest_master
title = title.replace("%npca", "the culprit")
title = title.replace("%npcb", quest_master.name)
title = title.replace("%item", quest_item.name)
ai_master.title = title
ai_master.owner = quest_master
# replace dialogue placeholders
success_dialogue = [e.replace("%npcb", quest_master.name).replace("%item", quest_item.name) \
for e in success_dialogue]
# success_dialogue = success_dialogue.replace("%b", quest_master.name)
# success_dialogue = success_dialogue.replace("%i", quest_item.name)
ai_master.success_dialogue = success_dialogue
def add_random_quest(game_map, game_objects):
"""
give a quest using random characters.
"""
dialogues = (
"I have lost my %item,\nPlease help me find it."
,"I played in the garden and\nnow my %item is missing.\nHelp me find it?"
,"I lost my %item,\n please find it for me Top Dog!"
,"%npca took my %item.\nCan you bring it back for me?"
)
thankyous = (
("You found my %item,\nThank you!")
,("My %item!\nI hope %npca was not\nmuch trouble.\nMy Hero!")
,("Thanks for returning my %item.\nI will remember this moment!")
,("Thank you, my %item is safe again.")
)
title = "%npcb: find %item"
dialogue = random.choice(dialogues)
success = random.choice(thankyous)
quest_item = get_toy()
quest_master = get_random_npc()
quest_npc = None
# use a quest npc to carry the item
if dice(2):
# is it hostile?
if dice(6): #!
quest_npc = get_random_npc(attack_rating=1)
else:
quest_npc = get_random_npc()
dialogue = dialogue.replace("%npca", quest_npc.name)
place_on_map(game_map, game_objects, quest_npc)
game_objects.append(quest_npc)
quest_item.x = 0
else:
dialogue = dialogue.replace("%npca", "some thief")
place_on_map(game_map, game_objects, quest_item)
game_objects.append(quest_item)
# set quest giver dialogue
dialogue = dialogue.replace("%item", quest_item.name)
quest_master.action_ai.dialogue_text = dialogue
# place all on the map
place_on_map(game_map, game_objects, quest_master)
game_objects.append(quest_master)
# glue the quest together
link_quest(game_map, game_objects
, title, quest_master, quest_item
, quest_npc, success_dialogue=[success])
#=================================================================[[ NPC's ]]
def get_random_npc(npc_char=None, attack_rating=None, dialogue_text=None):
"""
get a randomly generated npc.
"""
dna_bank = {
"m": "mouse"
,"j": "monkey"
,"d": "dog"
,"D": "big dog"
,"c": "cat"
,"s": "squirrel"
,"b": "bird"
,"p": "parrot"
}
if not npc_char:
npc_char = random.choice(dna_bank.keys())
# NPC
npc = cls.AnimalBase()
npc.blocking = True
npc.char = npc_char
npc.fgcolor = libtcod.light_sky
npc.name = dna_bank[npc_char]
npc.move_step = random.randint(1, 3)
npc.dialogue_text = dialogue_text
# move AI
mov = cls.MoveAI(npc)
npc.move_ai = mov
mov.behaviour = random.choice((cls.MoveAI.NEUTRAL, cls.MoveAI.SKITTISH))
# action AI
act = cls.ActionAI(npc)
if attack_rating:
if attack_rating > 0:
mov.behaviour = cls.MoveAI.HUNTING
act.attack_rating = attack_rating
act.hostile = True
npc.action_ai = act
return npc
def spawn_level_objects(game_map, game_level):
"""
create a bunch of level objects.
"""
toys = 0
npcs = 0
food = 0
objects = []
# level progression grid format
# --------------------------------
# NPC | TOYS | FOOD |
# --------------------------------
# (min,max, | | |
# attack_rating) | |
# |,(min,max) |
# | ,(min,max)|
progression = (
((0, 1, 1) ,(1, 2) ,(1, 1))
,((0, 1, 1) ,(1, 2) ,(1, 1))
,((0, 1, 1) ,(1, 3) ,(1, 1))
,((0, 2, 1) ,(1, 3) ,(1, 1))
,((1, 2, 2) ,(2, 3) ,(1, 2))
,((1, 2, 2) ,(2, 3) ,(1, 2))
,((1, 3, 2) ,(2, 4) ,(1, 2))
,((1, 3, 2) ,(2, 4) ,(1, 3))
,((2, 4, 3) ,(6, 9) ,(2, 3))
,((2, 4, 3) ,(2, 4) ,(2, 3))
)
prog = progression[game_level]
npcs = random.randint(prog[0][0], prog[0][1])
toys = random.randint(prog[1][0], prog[1][1])
food = random.randint(prog[2][0], prog[2][1])
# npcs
for item in range(npcs):
npc = get_random_npc(npc_char=None, attack_rating=random.randint(0, prog[0][2]))
place_on_map(game_map, objects, npc)
objects.append(npc)
# toys
for item in range(toys):
toy = get_toy()
place_on_map(game_map, objects, toy)
objects.append(toy)
# food
for item in range(food):
eat = get_food()
place_on_map(game_map, objects, eat)
objects.append(eat)
return objects
def get_random_dialogue():
# dlgs = ("Nice day today, isn't it?'",)
# return random.choice(dlgs)
return None
def add_random_npc(game_map, game_objects, npc_char=None, attack_rating=None, dialogue_text=None):
npc = get_random_npc()
npc.action_ai.dialogue_text = dialogue_text
place_on_map(game_map, game_objects, npc)
game_objects.append(npc)
def spawn_level_quests(game_map, game_objects, game_level):
"""
create quests based on the level.
"""
if game_level == 2:
add_random_quest(game_map, game_objects)
add_random_npc(game_map, game_objects
, npc_char=None, attack_rating=None
, dialogue_text="Ye, I know of the Fat Cats, the Mafioso..." \
"\n\nI'd watch your back if I were you, those Cats scratch!")
elif game_level == 3:
add_random_quest(game_map, game_objects)
add_random_npc(game_map, game_objects, npc_char=None
, attack_rating=None, dialogue_text=get_random_dialogue())
add_random_npc(game_map, game_objects
, npc_char=None, attack_rating=None
, dialogue_text="Ever had stitches in your snout?\n\n" \
"I had 3 stiches where " \
"the Mafioso scratched me. I refused to give them my dinner.")
elif game_level == 4:
add_random_quest(game_map, game_objects)
add_random_npc(game_map, game_objects, npc_char=None
, attack_rating=None, dialogue_text=get_random_dialogue())
add_random_npc(game_map, game_objects, npc_char=None
, attack_rating=None, dialogue_text=get_random_dialogue())
elif game_level == 5:
add_random_quest(game_map, game_objects)
add_random_quest(game_map, game_objects)
add_random_npc(game_map, game_objects, npc_char=None
, attack_rating=None, dialogue_text=get_random_dialogue())
elif game_level == 6:
add_random_quest(game_map, game_objects)
add_random_quest(game_map, game_objects)
add_random_quest(game_map, game_objects)
add_random_npc(game_map, game_objects, npc_char=None
, attack_rating=None, dialogue_text=get_random_dialogue())
add_random_npc(game_map, game_objects, npc_char=None
, attack_rating=None, dialogue_text=get_random_dialogue())
elif game_level == 7:
add_random_quest(game_map, game_objects)
add_random_quest(game_map, game_objects)
add_random_quest(game_map, game_objects)
add_random_npc(game_map, game_objects, npc_char=None
, attack_rating=None, dialogue_text=get_random_dialogue())
# elif game_level == 8:
#
# elif game_level == 9:
#
#
def spawn_level_storyline(game_map, game_objects, player):
"""
add some NPC's and dialogue for our doggy tail.
"""
if player.level == 1:
npc = get_random_npc(npc_char="b", attack_rating=None)
npc.name = "Shona the bird"
npc.picture = "icon-bird.png"
npc.see_message = "Shona (b) chirps you closer..."
npc.action_ai.dialogue_text = [
"Go to the %cright%c, find %cJulie the mouse%c to learn about " \
"quests... Good luck!\n^_^" % (C.COL2, C.COLS, C.COL2, C.COLS)
,"If you get thirsty running around, stand on some water to " \
"[d]rink.\n\nIf you get hungry, pick up some " \
"food and [e]at it.\n\nIf you have to [p]iddle" \
", stand next to something interesting for " \
"extra points ;)"
,"Hi Top Dog!" \
"\n\nWatch your health hearts and messages." \
"\n\nWalk over items to pick them up in your mouth." \
"\n\nYou can only carry one item at a time.\n\nWalk into other" \
" animals to talk or fight, depending if they are hostile."
]
npc_b = get_random_npc(npc_char="m", attack_rating=None)
npc_b.name = "Julie the mouse"
npc_b.picture = "icon-mouse.png"
npc_b.action_ai.dialogue_text = [
"The monkey stole my piece of cheese just now!" \
"\n\nCan you go get it back for me, pleeeeeease?" \
"\n\nThe monkey ran South, laughing like a maniac..."
,"Hi Top Dog, I am Julie the mouse. Can you help me?"
]
quest_item = get_food()
quest_item.name = "Julie's cheese"
quest_item.edible = False
npc_a = get_random_npc(npc_char="j", attack_rating=1)
npc_a.move_ai.behaviour = cls.MoveAI.NEUTRAL
npc_a.action_ai.dialogue_text = [
"You want %c*this*%c cheese? Ha! Not without a fight!" % (C.COL5, C.COLS)]
dlg_b = [
"I just got a birdy-gram...\n\nThe dog next door, Girly, is" \
" asking for you.\n\nIt is %c*important*%c.\n\nCrawl into " \
"the hole along the fence... go find her..." % (C.COL2, C.COLS)
,"Oh thank you Top Dog! Those monkeys are always trouble..." \
"\n\nOh, by the way..."
]
link_quest(game_map, game_objects
, "get Julie's cheese from monkey", quest_master=npc_b, quest_item=quest_item
, quest_npc=npc_a, success_dialogue=dlg_b, success_command=None
)
place_on_map(game_map, game_objects, player, near_xy=(2, 2))
place_on_map(game_map, game_objects, npc, near_xy=(player.x, player.y))
place_on_map(game_map, game_objects, npc_b, near_xy=(C.MAP_WIDTH, 2))
place_on_map(game_map, game_objects, npc_a, near_xy=(2, C.MAP_HEIGHT))
game_objects.extend((npc, npc_b, npc_a))
elif player.level == 2:
npc_a = get_random_npc(npc_char="d", attack_rating=None)
npc_a.name = "Girly the dog"
npc_a.picture = "icon-dog.png"
npc_a.action_ai.dialogue_text = [
"I don't know more, talk to other animals, they may know..."
,"I saw some really Fat Cats hanging around yesterday... " \
"mischievious they are, I bet they are behind this.\n\n" \
"Please help us find Puppy! Who knows what they will do to her..."
,"Hi Top Dog, Puppy was taken!"
]
# this quest will just give us a biscuit when we talk to Girly
q = cls.QuestAI()
q.owner = npc_a
q.item = get_food()
q.item.name = "Biscuit"
npc_a.quest_ai = q
# link the quest to the player. they will see it in their quest list
qdata = cls.QuestData(q.quest_id)
qdata.quest_id = q.quest_id
qdata.npc_name = npc_name = "Girly"
qdata.title = "Talk to Girly the dog"
player.give_quest(qdata, silent=False)
place_on_map(game_map, game_objects, npc_a)
game_objects.append(npc_a)
elif player.level == 3:
npc_b = get_random_npc(npc_char="s", attack_rating=None)
npc_b.see_message = "The Squirrel forages for nuts"
npc_b.action_ai.dialogue_text = (
"Ye, I know of the Fat Cats... the Mafioso they call themselves." \
"\n\nI'd watch your back if I were you, those Cats scratch!")
place_on_map(game_map, game_objects, npc_b)
game_objects.append(npc_b)
elif player.level == 4:
npc_b = get_random_npc(npc_char=None, attack_rating=None)
npc_b.char="C"
npc_b.name = "Fat Cat Charles"
npc_b.move_ai.behavior = cls.MoveAI.NEUTRAL
npc_b.picture = "icon-fat cat.png"
npc_b.action_ai.dialogue_text = [
"Find my nephew, Jinx, in the next yard. He can tell you how " \
"to find them..."
,"I don't like them for taking Puppy, they chased me away when " \
"I tried to stop them."
,"Yes I'm a Fat Cat Mafioso, we aren't all bad, just that..." \
"\n\nwell, a couple of the other Cats are naughty, like mischief too much."
,"*hiss and sputters*\n\nHey hey take it easy, rover!"
]
place_on_map(game_map, game_objects, npc_b)
game_objects.append(npc_b)
elif player.level == 5:
npc_a = get_random_npc(npc_char="c", attack_rating=None)
npc_a.name = "Jinx the cat"
npc_a.picture = "icon-cat.png"
npc_a.action_ai.dialogue_text = [
"That should get their attention..."
,"The Mafioso cannot be found, but if you get their attention, " \
"they will find you.\n\nHere, take this Jingly Ball lying " \
"here, take it next door and go brag to the Monkey " \
"how you took it from me..."
,"My uncle Charlie sent you, huh? Well fine..." \
"\n\n*Jinx shoves a toy mouse to and fro*"]
place_on_map(game_map, game_objects, npc_a)
game_objects.append(npc_a)
# spawn a jingly ball toy nearby
toy = get_toy()
toy.name = "Jinx's Jingly Ball"
place_on_map(game_map, game_objects, toy, near_xy=(npc_a.x, npc_a.y))
game_objects.append(toy)
elif player.level == 6:
npc_a = get_random_npc(npc_char="p", attack_rating=None)
npc_a.name = "Shorty the Parrot"
npc_a.picture = "icon-parrot.png"
npc_a.action_ai.dialogue_text = [
"*squawk* I've been keeping an eye on those Monkeys. *creeek*" \
" I don't trust them." \
"\n\nI bet they work with those Fat Cats, and they steal my seed!"
]
place_on_map(game_map, game_objects, npc_a)
game_objects.append(npc_a)
npc_b = get_random_npc(npc_char="j", attack_rating=None)
npc_b.name = "Crazy the Monkey"
npc_b.picture = "icon-monkey.png"
npc_b.action_ai.dialogue_text = [
"You're a pretty crafty hound, taking that cat's Jingly Ball.\n\n" \
"I have some friends who need animals like you.\n\n" \
"Let me go talk to some friends..."
]
place_on_map(game_map, game_objects, npc_b)
game_objects.append(npc_b)
elif player.level == 7:
npc_b = get_random_npc(npc_char=None, attack_rating=None)
npc_b.char="C"
npc_b.name = "Fat Cat Tiny"
npc_b.move_ai.behavior = cls.MoveAI.NEUTRAL
npc_b.picture = "icon-fat cat.png"
npc_b.action_ai.dialogue_text = [
"We still like your style, come on next door, maybe you can help us..."
,"Listen pal, it will take more than Jingly Balls to play with us, " \
"some advice: Stay clear of Jinx, or else..."
,"*grimmaces* So you're the Jingly Ball con? *purrrs*"
]
place_on_map(game_map, game_objects, npc_b)
game_objects.append(npc_b)
elif player.level == 8:
npc_a = get_random_npc(npc_char="p", attack_rating=None)
npc_a.name = "Tweety the Parrot"
npc_a.picture = "icon-parrot.png"
npc_a.action_ai.dialogue_text = [
"*squawks* Oh you gave me a fright!\n\nI'm watching all those Fat Cats " \
"across the other side of the yard. I wonder what they are up to..."
]
place_on_map(game_map, game_objects, npc_a, near_xy=(player.x, player.y))
game_objects.append(npc_a)
# make a gang of Fat Cats. place a lead in front to meet you with dialogue.
# determine the angle relative to the player
gang_xy = None
opp_x = C.MAP_WIDTH - player.x
# opp_y = C.MAP_HEIGHT - player.y
# mid_x = C.MAP_WIDTH / 2
mid_y = C.MAP_HEIGHT / 2
gang_xy = (opp_x, mid_y)
lead_xy = None
if player.x < 5:
# place lead to the left of the gant
lead_xy = (gang_xy[0] - 5, gang_xy[1])
else:
# place lead to the right of the gant
lead_xy = (gang_xy[0] + 5, gang_xy[1])
# make thee Fat Cats
for i in range(3):
npc_b = get_random_npc(npc_char=None, attack_rating=1)
npc_b.char="C"
npc_b.name = "Mafioso %s" % (i)
npc_b.action_ai.hostile = True
npc_b.move_ai.behavior = cls.MoveAI.HUNTING
place_on_map(game_map, game_objects, npc_b, near_xy=gang_xy)
game_objects.append(npc_b)
# and the lead
npc_c = get_random_npc(npc_char=None, attack_rating=1)
npc_c.char="C"
npc_c.name = "Mafioso Boss"
npc_c.action_ai.hostile = True
npc_c.move_ai.behavior = cls.MoveAI.HUNTING
npc_c.picture = "icon-fat cat.png"
npc_c.action_ai.dialogue_text = [
"In fact, I setup this 'meeting' to trick you. If you want this Puppy " \
"you have to go through US first!"
,"We hear you are looking for this Puppy. You probably thought we want " \
"your help...."
]
place_on_map(game_map, game_objects, npc_c, near_xy=lead_xy)
game_objects.append(npc_c)
# tutu the hostage bird
npc_d = get_random_npc(npc_char="b", attack_rating=None)
npc_d.name = "Tutu the bird"
npc_d.picture = "icon-bird.png"
npc_d.action_ai.dialogue_text = [
"They keep the Puppy in the next yard, go rescue him, quickly!"
,"Thank you for chasing them away! I thought they were going to eat me alive!"
]
place_on_map(game_map, game_objects, npc_d, near_xy=gang_xy)
game_objects.append(npc_d)
elif player.level == 9:
# carryable puppy npc
npc_a = get_random_npc(npc_char=None, attack_rating=None)
npc_a.char = "P"
npc_a.name = "Puppy"
npc_a.tag = "puppy"
npc_a.picture = "icon-puppy.png"
npc_a.move_ai.behavior = cls.MoveAI.NEUTRAL
npc_a.move_step = 1
npc_a.action_ai.dialogue_text = [
"We better go, before they return..."
,"Top Dog! I am so glad to see you!\n\nThose Fat Cats are nasty, " \
"but I bit a couple of them..."
]
place_on_map(game_map, game_objects, npc_a, near_xy=None)
game_objects.append(npc_a)
#===================================================================[[ Map ]]
def blank_map():
"""
Return a new, blank map array.
"""
# colors = (libtcod.darkest_lime, libtcod.darkest_green
# , libtcod.darkest_sea, libtcod.darkest_chartreuse)
newmap = [[ cls.ItemBase(
fgcolor=libtcod.darker_green
,bgcolor=libtcod.darker_green)
for y in range(C.MAP_HEIGHT)]
for x in range(C.MAP_WIDTH)]
return newmap
def get_fence():
panel = cls.ItemBase()
panel.name = "Fence"
panel.char = CHAR_FENCE
panel.bgcolor = libtcod.dark_sepia
panel.fgcolor = libtcod.dark_sepia
panel.blocking = True
panel.seethrough = False
return panel
def get_hole():
hole = cls.Hole()
hole.name = "Space/Enter crawls through this hole..."
hole.bgcolor = libtcod.darker_sepia
hole.fgcolor = libtcod.lighter_sepia
return hole
def place_fence_holes(game_map):
"""
Make a few random fence holes. Test they are at least next to grass
or foliage to crawl through.
"""
halfx = C.MAP_WIDTH / 2
halfy = C.MAP_HEIGHT / 2
for holes in range(random.randint(2, 4)):
while True:
x = random.randint(0, C.MAP_WIDTH - 1)
y = random.randint(0, C.MAP_HEIGHT - 1)
xo = 0
yo = 0
# snap the x/y to the nearest border
# but only x, or only y, depending on dice roll
if random.randint(0, 1) == 0:
if x < halfx:
x = 0
xo = 1
yo = y
else:
x = C.MAP_WIDTH - 1
xo = x - 1
yo = y
yo
else:
if y < halfy:
y = 0
yo = 1
xo = x
else:
y = C.MAP_HEIGHT - 1
yo = y - 1
xo = x
# test there is a space or foliage alongside
if game_map[xo][yo].isblank():
game_map[x][y] = get_hole()
break
def build_fence(game_map):
"""
Outline the yard with a fence like structure.
"""
for y in range(C.MAP_HEIGHT - 0):
game_map[0][y] = get_fence()
game_map[C.MAP_WIDTH - 1][y] = get_fence()
for x in range(C.MAP_WIDTH - 0):
game_map[x][0] = get_fence()
game_map[x][C.MAP_HEIGHT - 1] = get_fence()
place_fence_holes(game_map)
def plant_foliage(game_map):
"""
Plant some trees and things onto the map.
"""
# make a few large thickets
# spawn_foliage(game_map, amount=2, thicket_size=12, density=2)
# make a few smaller, denser thickets
# spawn_foliage(game_map, amount=2, thicket_size=6, density=6)
# spread some single greens around the map
spawn_foliage(game_map, amount=10, thicket_size=1, density=1)
# make some wet spots
spawn_pond(game_map, amount=3, pond_size=10, density=2)
def get_brick(color=libtcod.dark_grey):
"""
Make a brick tile.
"""
brick = cls.ItemBase()
brick.blocking = True
brick.seethrough = False
brick.name = "wall"
brick.char = CHAR_BRICK
brick.fgcolor = libtcod.darker_grey
brick.bgcolor = color
return brick
def get_path():
"""
Make a gravel tile.
"""
t = cls.ItemBase()
t.blocking = False
t.seethrough = True
t.fgcolor = random.choice((libtcod.darkest_green, libtcod.darkest_sea, libtcod.darkest_chartreuse))
t.char = CHAR_GRAVEL
t.name = ""
return t
def get_tile(char="?", fgcolor=libtcod.white, bgcolor=libtcod.red
, blocks=False, seethrough=True, name="", msg=None):
"""
Make a stone tile.
"""
t = cls.ItemBase()
t.blocking = blocks
t.seethrough = seethrough
t.bgcolor = bgcolor
t.fgcolor = fgcolor
t.char = char
t.name = name
t.message = msg
return t
def flip_map(game_map):
"""
Transform the map by mirroring it on X/Y.
"""
# mirror x
if random.randint(0, 1) == 0:
game_map.reverse()
# mirror y
if random.randint(0, 1) == 0:
for e in game_map:
e.reverse()
def read_map_file(map_index):
"""
Read an ASCII map file and return it as a list of lines.
"""
f = open(os.path.join('data', 'maps', 'map%s' % (map_index)))
contents = f.read(3000)
f.close()
map_data = contents.split("\n")
return map_data
def map_from_ascii(game_map, maps_available):
"""
Load map tiles from an ascii representation.
"""
# here we can map ascii values to our tile objects
# since the ascii maps can't contain special chars
tile_lookup = {
"B": "get_brick(libtcod.darker_grey)"
,"R": "get_brick(libtcod.darker_flame)"
,"=": "get_tile(CHAR_STONE, fgcolor=libtcod.darkest_grey, bgcolor=libtcod.darker_green)"
,"-": "get_tile('-', fgcolor=libtcod.dark_green, bgcolor=libtcod.dark_green)"
,"&": "get_tile('&', bgcolor=libtcod.darkest_yellow, fgcolor=random.choice((libtcod.darkest_yellow, libtcod.darkest_lime, libtcod.darker_gray)), blocks=True, name='compost', msg='the compost stinks good!')"
,"[": "get_tile('[', bgcolor=libtcod.dark_grey, fgcolor=libtcod.light_grey, blocks=True, seethrough=False, name='car')"
,"#": "get_fence()"
,CHAR_GRAVEL: "get_path()"
,";": "get_path()"
,CHAR_WATER: "get_pool_tile()"
,'f': "get_flower()"
,'t': "get_tree()"
,'b': "get_bush()"
}
# get_tile(char="?", color=libtcod.white, blocks=False, seethrough=True, name="")
#char="?", fgcolor=libtcod.white, bgcolor=libtcod.red
# , blocks=False, seethrough=True, name="", msg=None
map_data = read_map_file(random.randint(1, maps_available))
for y in range(C.MAP_HEIGHT - 1 - 3):
for x in range(C.MAP_WIDTH - 1 - 3):
asciic = map_data[y][x]
if asciic in tile_lookup:
tile = eval(tile_lookup[asciic])
game_map[x + 2][y + 2] = tile
def count_available_maps():
"""
Get the count of maps available.
"""
for num in range(100):
if not os.path.exists(os.path.join("data", "maps", "map%s" % (num + 1))):
return num
break
def generate_map(maps_avail):
"""
Generate a level map, plant trees and objects and NPC's.
"""
game_map = blank_map()
map_from_ascii(game_map, maps_avail)
flip_map(game_map)
plant_foliage(game_map)
build_fence(game_map)
fov_map = libtcod.map_new(C.MAP_WIDTH, C.MAP_HEIGHT)
for y in range(C.MAP_HEIGHT - 1):
for x in range(C.MAP_WIDTH - 1):
libtcod.map_set_properties(fov_map, x, y
,game_map[x][y].seethrough
,not game_map[x][y].blocking and \
not game_map[x][y].drinkable)
path_map = libtcod.path_new_using_map(fov_map)
return game_map, fov_map, path_map
#===============================================================[[ Libtcod ]]
def init_libtcod():
startup_msg = ("analyzing air quality...", "calculating primordial soup..."
,"reading the future...", "carbon dating your hard drive..."
,"finding prime numbers...")
print(random.choice(startup_msg))
libtcod.console_set_custom_font('data/fonts/terminal12x12_gs_ro.png',
libtcod.FONT_TYPE_GREYSCALE |
libtcod.FONT_LAYOUT_ASCII_INROW)
libtcod.console_init_root(C.SCREEN_WIDTH, C.SCREEN_HEIGHT,
'top dog -- v%s' % (C.VERSION), C.FULLSCREEN)
libtcod.sys_set_fps(C.LIMIT_FPS)
# default font color
libtcod.console_set_default_foreground(0, libtcod.white)
# set color control codes for inline string formatting
# listed by priority: think defcon levels
# high alert, priority one
libtcod.console_set_color_control(libtcod.COLCTRL_1
,libtcod.light_red
,libtcod.black)
# warning, danger will robinson
libtcod.console_set_color_control(libtcod.COLCTRL_2
,libtcod.light_yellow
,libtcod.black)
# informational, you got a quest item
libtcod.console_set_color_control(libtcod.COLCTRL_3
,libtcod.light_green
,libtcod.black)
# tile and npc names
libtcod.console_set_color_control(C.COL4
,libtcod.light_azure
,libtcod.black)
# all other words
libtcod.console_set_color_control(libtcod.COLCTRL_5
,libtcod.white
,libtcod.black)
return libtcod.console_new(C.MAP_WIDTH, C.MAP_HEIGHT)
#=============================================================[[ Unit Test ]]
if __name__ == "__main__":
pass