Added an initial brainstorm for a more fully-featured tutorial multiplayer game "Battle for Evennia". The idea is to use this as a basis for a series of tutorials on building a relatively complete game in Evennia. The details will probably change, so putting it up for comments from the community.

This commit is contained in:
Griatch 2012-03-31 21:10:34 +02:00
parent fcc338c027
commit 75cc8bf1ad
2 changed files with 158 additions and 29 deletions

View file

@ -0,0 +1,139 @@
Battle for Evennia
------------------
Evennia contrib - Griatch 2012 (WORK IN PROGRESS)
This is the beginnings of what will be a tutorial for building a
simple yet still reasonably playable and not-quite-bog-standard
starting game in Evennia. The tutorial text itself will eventually be
found from the Dev blog and from the wiki.
Ideas & Initial Brainstorm
---------------------------
This is to be a hack&slash game. Characters fight mobiles and each
other for random loot and better weapons. The highscore is based on
most accumulated gold. They can sell loot to NPC merchants for gold,
and also buy stuff others sold there (spending gold). Characters get
better in the skills they use (no levels). They automatically collect
loot when they kill things, and they cannot drop it (but they can give
it away and, most importantly sell it). Death sends the player back to
a starting position, but gives all but their weakest gear to their
nemesis (they keep all their gold though).
Inventory of code we need:
- Loot/Equipment lists of Weapons, Armour, Potions and Spells - maybe partly randomly generated.
- Way to spawn in-game objects based on the loot lists
- Character creation module (choose skills, attributes, assigns starting gear)
- 3 Attributes, about 10 skills (some magic?)
- Experience -> skill increase code
- Skill success code - same between PCs as between NPC and PC
- Combat code (twitch-based? Turn-based? Turn based seems easier to balance. Same for NPC vs PC and PC vs PC)
- Mobile code (same for NPCs and enemies)
- 'Give' mechanism (should require consent by receiver)
- No quests, for simplicity. Use gold as a highscore.
- Death respawn mechanism
Elaboration based on Brainstorm
-------------------------------
* Loot/Equipment lists and spawn - These could be global-level
dictionaries in a module. Each dictionary gives info such as name,
description and typeclass. Attributes could be set or
randomized. The loot-spawner (probably a handler tied to a dead
mob, treasure chest etc) would use utils.variable_from_module to
extract a random item-template.
* Characters have 3 attributes: Wile, Strength and Agility. At
creation, they distribute points between them. Wile is used for
bartering with merchants, and using Magic. Strength determines
hand-weapon damage and how heavy armour can be worn. Agility
determines ability to dodge, initiative and using lighter weapons.
Health is based on an average of all three attributes (i.e. all
chars start with the same health).
* Skills are as follows (may change):
- Long blades (str) ability to hit with swords and also axes.
- Blunt (str) usage of blunt weapons like clubs. Good on armoured foes.
- Spears (agi) usage of spears and hillebards. Bonus on first attack, minus on initiative.
- Daggers (agi) usage of daggers and short blades. Bonus on initiative, bad on armour
- Unarmoured (agi) usage of your fists and feet. Very fast. Bad on armour.
- Dodge (agi) avoiding blows by swift footwork
- Feint (agi) faign attacks to keep the enemy guessing
- Shield (str) absorbing hits with a shielf
- Platemail (str) utilizing heavy armour
- Chainmail (max(str, agi)) utilizing medium armour
- Leather (agi) utilizing light armour
- Barter (wil) barter with merchants for a good price
- Magic (wil) use of single-use magical scrolls to achieve various effects
- Potions (wil) making the best of potions with various effects
- Heal (wil) fixing yourself (or a friend) up between combat. Also judge opponent's wounds.
* Experience simply rises upon kills and is distributed between the
skills used in the battle (so we need to log this). After N amount of
XP in a skill, that skill automatically goes up one
point. Increasing skills at least N points in 3+ different skills
of a certain type (str, agi, wil) will increase the most trained
Attribute by one point.
* Skill success is a comparison between the value of a random.gauss
centered around the attacker's skill value vs the result of a
random.gauss centered on the defender's skill. Certain
weapons/defense combinations might be especially effective against
one another (or not). The difference is the base damage, then
adjusted by weapon and armour. In the case of bartering, skill
challenge is between barter skill of both sides; difference
influences the discount/higher price offered for selling/buying.
* Attacking another player or NPC will start a combat queue.
Combat happens in turns. Each turn each player may do two actions,
picking among the following:
- attack
- parry (with weapon)
- shield
- feint
- dodge
- flee <direction>
- block (anti-flee)
Emoting is free in each round, but movement is forbidden unless one
tries to flee (agi challenge, or cancelled by block action). All
combattants involved in a fight submits their actions, then combat
is resolved simultaneously by the code. Order of the two actions
matter, so for example if both attack, neither is trying to parry,
but may hit each other simultaneously. If both parry, shield or
dodge, it means both are dancing about each other. If one feints
and the other parries or dodges, they will have a disadvantage on
the next defensive movement. A successful parry will give the
parried attacker a disadvantage on their next attack. And so on.
Another player may "join the queue" at any time by attacking one of
the combatting PCs. They get to insert their actions together with
the rest on the next round. A round should probably have a timeout
to avoid a Character clogging the queue.
* Mobiles will use "a global ticker system" where they
subscribe. They act the same way as PCs in combat, except with a
semi- random selection of actions they take (they will probably be
more predictable than PCs). Adding aggressive and passive mobiles
should be straightforward, as well as un-killable ones (merchants).
* The inventory of a defeated enemy is automatically transferred to
the winner's inventory. If there are many alternative pieces of
equipment, they get to keep the weakest one, otherwise it's all
transferred. There are no limits to carrying except the fear of
losing gear. This should hopefully prevent hoarding of good items.
One can give item(s) to another player - that player must then
conceed to receiving it (use Y/N module in contrib.menusystem).
There is no way of dropping items on the ground; one must either
give them away or sell them for gold to a merchant.
* Gold is used for buying items from merchants, but is also the
highscore. Whereas sell prices are fixed, buy prices are not fixed
but is based on a percentage of the gold carried, adjusted by the
barter skill (this should defeat inflation quite effectively). Items
sold to merchants are made available for other players to buy.
* Death means loosing inventory (except weakest item, as mentioned),
but no loss of gold. Otherwise death is cheap - one respawns at a
random starting position (probably needing special-aliased rooms to
use for this - maybe with one-way exits).

View file

@ -603,48 +603,38 @@ def mod_import(mod_path, propname=None):
return mod_prop
return mod
def variable_from_module(modpath, variable, default=None):
def variable_from_module(modpath, variable=None, default=None):
"""
Retrieve a given variable from a module. The variable must be
defined globally in the module. This can be used to implement
arbitrary plugin imports in the server.
Retrieve a variable from a module. The variable must be defined
globally in the module. If no variable is given, a random variable
is returned from the module.
If module cannot be imported or variable not found, default
If module cannot be imported or given variable not found, default
is returned.
"""
if not modpath:
return None
return default
try:
mod = __import__(modpath, fromlist=["None"])
return mod.__dict__.get(variable, default)
except ImportError:
return default
if variable:
# try to pick a named variable
return mod.__dict__.get(variable, default)
else:
# random selection
mvars = [val for key, val in mod.__dict__.items() if not key.startswith("_")]
return mvars and random.choice(mvars)
def string_from_module(modpath, variable=None, default=None):
"""
This is a variation used primarily to get login screens randomly
from a module.
This obtains a string from a given module python path. Using a
specific variable name will also retrieve non-strings.
The variable must be global within that module - that is, defined
in the outermost scope of the module. The value of the variable
will be returned. If not found, default is returned. If no variable is
given, a random string variable is returned.
This is useful primarily for storing various game strings in a
module and extract them by name or randomly.
This is a wrapper for variable_from_module that requires return
value to be a string to pass. It's primarily used by login screen.
"""
mod = __import__(modpath, fromlist=[None])
if variable:
return mod.__dict__.get(variable, default)
else:
mvars = [val for key, val in mod.__dict__.items()
if not key.startswith('_') and isinstance(val, basestring)]
if not mvars:
return default
return mvars[random.randint(0, len(mvars)-1)]
val = variable_from_module(modpath, variable=variable, default=default)
if isinstance(val, basestring):
return val
return default
def init_new_player(player):
"""