├── lampmud
├── env
│ ├── __init__.py
│ ├── instancemgr.py
│ ├── movement.py
│ └── instance.py
├── comm
│ ├── __init__.py
│ └── broadcast.py
├── editor
│ ├── __init__.py
│ ├── imports.py
│ ├── shared.py
│ ├── scripts.py
│ └── start.py
├── lpmud
│ ├── combat
│ │ ├── __init__.py
│ │ ├── system.py
│ │ └── fight.py
│ ├── feature
│ │ ├── __init__.py
│ │ └── touchstone.py
│ ├── __init__.py
│ ├── appstart.py
│ ├── server.py
│ ├── archetype.py
│ ├── newsetup.py
│ ├── article.py
│ ├── attributes.py
│ ├── env.py
│ ├── mobile.py
│ └── player.py
├── setup
│ ├── __init__.py
│ ├── update.py
│ └── engine.py
├── __init__.py
├── server
│ ├── __init__.py
│ └── messages.py
├── model
│ ├── __init__.py
│ ├── script.py
│ ├── area.py
│ ├── race.py
│ ├── mobile.py
│ ├── item.py
│ ├── player.py
│ └── article.py
└── mud
│ ├── __init__.py
│ ├── tools.py
│ ├── inventory.py
│ ├── action.py
│ ├── chat.py
│ ├── socials.py
│ └── target.py
├── webclient
├── lampost.png
├── mud
│ ├── css
│ │ └── mud.css
│ ├── sound
│ │ ├── atone.mp3
│ │ ├── beep_ping.mp3
│ │ └── sound_list.html
│ ├── image
│ │ └── friendNotify.png
│ ├── view
│ │ ├── messages_tab.html
│ │ ├── system_msg.html
│ │ ├── channel_tab.html
│ │ ├── player_msg.html
│ │ ├── data_tabs.html
│ │ ├── player_list_tab.html
│ │ ├── friend_req_msg.html
│ │ ├── status_tab.html
│ │ └── main.html
│ ├── dialogs
│ │ ├── select_character.html
│ │ ├── password_reset.html
│ │ ├── forgot_password.html
│ │ ├── forgot_name.html
│ │ ├── new_account.html
│ │ └── new_character.html
│ └── js
│ │ ├── status.js
│ │ ├── character.js
│ │ ├── storage.js
│ │ ├── comm.js
│ │ └── data.js
├── editor
│ ├── css
│ │ └── editor.css
│ ├── view
│ │ ├── no_item.html
│ │ ├── data_error.html
│ │ ├── outside_edit.html
│ │ ├── social_cheat.html
│ │ ├── display.html
│ │ ├── input_list.html
│ │ ├── imports.html
│ │ ├── simple_list.html
│ │ ├── option_list.html
│ │ ├── edit_list.html
│ │ ├── value_set.html
│ │ ├── editor_main.html
│ │ ├── area.html
│ │ ├── admin_view.html
│ │ ├── script.html
│ │ ├── user.html
│ │ ├── mobile.html
│ │ ├── defense.html
│ │ ├── social.html
│ │ ├── race.html
│ │ ├── config.html
│ │ ├── attack.html
│ │ └── player.html
│ ├── panels
│ │ ├── action_script.html
│ │ ├── article_load.html
│ │ ├── shadow_script.html
│ │ ├── modify_exit.html
│ │ ├── feature.html
│ │ ├── modify_script.html
│ │ ├── touchstone.html
│ │ ├── extra.html
│ │ ├── new_script.html
│ │ ├── room_reset.html
│ │ ├── new_exit.html
│ │ └── entrance.html
│ ├── fragments
│ │ ├── owner_id.html
│ │ ├── read_access.html
│ │ ├── write_access.html
│ │ ├── aliases.html
│ │ └── script_list.html
│ ├── js
│ │ ├── display_editor.js
│ │ ├── admin.js
│ │ ├── editor_filters.js
│ │ ├── imports_editor.js
│ │ ├── area_editor.js
│ │ ├── player_editor.js
│ │ ├── socials_editor.js
│ │ ├── feature_editors.js
│ │ └── skills_editor.js
│ └── dialogs
│ │ ├── script_selector.html
│ │ └── select_db.html
├── common
│ ├── dialogs
│ │ ├── loading.html
│ │ ├── alert.html
│ │ └── prompt.html
│ └── js
│ │ ├── directives.js
│ │ └── autofill-event.js
└── lampost.html
├── .gitignore
├── .gitattributes
├── lampost_mud.py
├── lampost_tools.py
├── lampost_setup.py
├── LICENSE.txt
├── README.md
└── conf
└── main.yaml
/lampmud/env/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lampmud/comm/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lampmud/editor/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lampmud/lpmud/combat/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lampmud/setup/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lampmud/__init__.py:
--------------------------------------------------------------------------------
1 | from . import server
2 |
--------------------------------------------------------------------------------
/lampmud/server/__init__.py:
--------------------------------------------------------------------------------
1 | from . import messages
2 |
--------------------------------------------------------------------------------
/lampmud/lpmud/feature/__init__.py:
--------------------------------------------------------------------------------
1 | from . import store, touchstone
2 |
--------------------------------------------------------------------------------
/webclient/lampost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/genzgd/Lampost-Mud/HEAD/webclient/lampost.png
--------------------------------------------------------------------------------
/webclient/mud/css/mud.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | overflow-y: hidden;
4 | }
5 |
--------------------------------------------------------------------------------
/lampmud/model/__init__.py:
--------------------------------------------------------------------------------
1 | from . import area, article, entity, item, mobile, player, race, script
2 |
--------------------------------------------------------------------------------
/lampmud/mud/__init__.py:
--------------------------------------------------------------------------------
1 | from . import target, immortal, group, socials, inventory, chat, mudcore
2 |
--------------------------------------------------------------------------------
/webclient/mud/sound/atone.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/genzgd/Lampost-Mud/HEAD/webclient/mud/sound/atone.mp3
--------------------------------------------------------------------------------
/webclient/editor/css/editor.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | }
4 |
5 | layout-bar {
6 | height: 20px;
7 | }
--------------------------------------------------------------------------------
/lampmud/lpmud/__init__.py:
--------------------------------------------------------------------------------
1 | from . import attributes, entity, player, mobile, archetype, feature, env, article, server
2 |
--------------------------------------------------------------------------------
/webclient/mud/sound/beep_ping.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/genzgd/Lampost-Mud/HEAD/webclient/mud/sound/beep_ping.mp3
--------------------------------------------------------------------------------
/webclient/mud/image/friendNotify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/genzgd/Lampost-Mud/HEAD/webclient/mud/image/friendNotify.png
--------------------------------------------------------------------------------
/webclient/mud/sound/sound_list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/webclient/editor/view/no_item.html:
--------------------------------------------------------------------------------
1 |
2 | No item currently selected.
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.idea
3 | src_ext
4 | data
5 | webclient/local_lib
6 | webclient/fonts
7 | webclient/test.html
8 | *.log
9 | dev
10 |
11 |
--------------------------------------------------------------------------------
/webclient/editor/panels/action_script.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.py text eol=lf
2 | *.js text eol=lf
3 | *.html text eol=lf
4 | *.js text eol=lf
5 | *.css text eol=lf
6 | .gitattributes text eol=lf
7 | .gitignore text eol=lf
--------------------------------------------------------------------------------
/webclient/editor/view/data_error.html:
--------------------------------------------------------------------------------
1 |
2 | ×
3 | {{errors[type]}}
4 |
5 |
--------------------------------------------------------------------------------
/lampmud/model/script.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbo import ChildDBO
2 | from lampost.gameops.script import UserScript
3 |
4 |
5 | class MudScript(UserScript, ChildDBO):
6 | dbo_key_type = 'script'
7 | dbo_parent_type = 'area'
8 |
--------------------------------------------------------------------------------
/webclient/editor/view/outside_edit.html:
--------------------------------------------------------------------------------
1 |
2 | ×
3 | Object updated by another user.
4 |
5 |
--------------------------------------------------------------------------------
/webclient/mud/view/messages_tab.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/webclient/common/dialogs/loading.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lampmud/lpmud/appstart.py:
--------------------------------------------------------------------------------
1 | from importlib import import_module
2 |
3 | from lampost.di import resource
4 |
5 | from lampmud.lpmud.combat import system
6 |
7 |
8 | def start_engine(args):
9 | import_module('lampmud.editor.start')
10 | resource.register('action_system', system)
11 |
--------------------------------------------------------------------------------
/webclient/editor/fragments/owner_id.html:
--------------------------------------------------------------------------------
1 |
2 | Owner Id
3 |
5 |
6 |
--------------------------------------------------------------------------------
/webclient/editor/fragments/read_access.html:
--------------------------------------------------------------------------------
1 |
2 | Read Access
3 |
5 |
6 |
--------------------------------------------------------------------------------
/lampmud/model/area.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbo import ParentDBO
2 | from lampost.db.dbofield import DBOField
3 |
4 |
5 | class Area(ParentDBO):
6 | dbo_key_type = "area"
7 | dbo_set_key = "areas"
8 | dbo_children_types = ['room', 'mobile', 'article', 'script']
9 |
10 | name = DBOField()
11 | desc = DBOField()
12 | next_room_id = DBOField(0)
13 |
--------------------------------------------------------------------------------
/webclient/editor/fragments/write_access.html:
--------------------------------------------------------------------------------
1 |
2 | Write Access
3 |
5 |
6 |
--------------------------------------------------------------------------------
/webclient/mud/view/system_msg.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{msgTime(msg)}}
4 | ×
5 |
6 |
{{msg.content}}
7 |
--------------------------------------------------------------------------------
/lampmud/mud/tools.py:
--------------------------------------------------------------------------------
1 | def combat_log(source, message, target=None):
2 | if hasattr(source.env, 'combat_log'):
3 | try:
4 | message = message.combat_log()
5 | except AttributeError:
6 | try:
7 | message = message()
8 | except TypeError:
9 | pass
10 | source.env.broadcast(s=message, source=source, target=target)
11 |
--------------------------------------------------------------------------------
/webclient/mud/view/channel_tab.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/lampmud/lpmud/server.py:
--------------------------------------------------------------------------------
1 | from lampost.server.link import link_route
2 | from lampost.di.resource import Injected, module_inject
3 |
4 | db = Injected('datastore')
5 | module_inject(__name__)
6 |
7 |
8 | @link_route('new_char_data')
9 | def _new_char_data(**_):
10 | return {'races': {race.dbo_id: _race_dto(race) for race in db.load_object_set('race')}}
11 |
12 |
13 | def _race_dto(race):
14 | return {'name' : race.name, 'desc': race.desc}
15 |
--------------------------------------------------------------------------------
/webclient/mud/view/player_msg.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{msgTime(msg)}}
4 | ×
5 |
6 |
{{msg.content}}
7 |
-- {{msg.source}}
8 |
--------------------------------------------------------------------------------
/webclient/editor/js/display_editor.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').controller('DisplayEditorCtrl', ['$scope', 'lpRemote', 'lpEvent', function ($scope, lpRemote) {
2 |
3 | $scope.updateDisplays = function () {
4 | lpRemote.request('editor/display/update', {displays: $scope.displays}, true);
5 | };
6 |
7 | lpRemote.request('editor/display/list').then(function (displays) {
8 | $scope.displays = displays;
9 | $scope.ready = true;
10 | })
11 |
12 | }]);
13 |
--------------------------------------------------------------------------------
/webclient/editor/view/social_cheat.html:
--------------------------------------------------------------------------------
1 |
2 |
Social/Message Cheat Sheet
3 |
4 |
5 |
6 |
7 | ${{token.id}}
8 | {{token.token}}
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lampost_mud.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from lampost.setup import startargs
4 | from lampost.util import logging
5 |
6 |
7 | if __name__ != "__main__":
8 | print("Invalid usage")
9 | sys.exit(2)
10 |
11 | args = startargs.main_parser.parse_args()
12 | logging.init_config(args)
13 | logging.root_logger.info("Started with args {}", args)
14 |
15 | from lampost.di import resource
16 | resource.register('log', logging.LogFactory())
17 |
18 | from lampmud.setup import engine
19 | engine.start(args)
20 |
--------------------------------------------------------------------------------
/webclient/mud/view/data_tabs.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lampost_tools.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | if __name__ != "__main__":
4 | print("Invalid usage")
5 | sys.exit(2)
6 |
7 | from lampost.util import logging
8 | from lampost.setup import startargs
9 |
10 | args = startargs.tools_parser.parse_args()
11 |
12 | logging.init_config(args)
13 | logging.root_logger.info("Started tools with args {}", args)
14 |
15 | # We set the logging configuration before importing other modules so that the root logger is properly configured
16 | from lampost.setup import tools
17 |
18 | getattr(tools, args.op)(args)
19 |
--------------------------------------------------------------------------------
/webclient/editor/view/display.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Default Display
4 |
5 | Update
6 |
7 |
8 |
9 |
10 |
{{display.desc}}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/webclient/mud/view/player_list_tab.html:
--------------------------------------------------------------------------------
1 |
19 |
20 |
--------------------------------------------------------------------------------
/lampmud/model/race.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbo import KeyDBO, OwnerDBO
2 | from lampost.db.dbofield import DBOField, DBOLField
3 |
4 | base_attr_value = 5
5 |
6 |
7 | class PlayerRace(KeyDBO, OwnerDBO):
8 | dbo_key_type = "race"
9 | dbo_set_key = "races"
10 |
11 | attr_list = []
12 |
13 | name = DBOField("Unnamed")
14 | desc = DBOField('')
15 | base_attrs = DBOField({})
16 | start_room = DBOLField(dbo_class_id='room')
17 | start_instanced = DBOField(False)
18 |
19 | @property
20 | def new_dto(self):
21 | dto = super().new_dto
22 | dto['base_attrs'] = {attr_name: base_attr_value for attr_name in self.attr_list}
23 | return dto
24 |
--------------------------------------------------------------------------------
/webclient/editor/panels/article_load.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Load Target
5 |
7 |
8 |
9 |
10 |
11 |
12 | Equip
13 |
14 |
15 |
--------------------------------------------------------------------------------
/webclient/common/dialogs/alert.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webclient/mud/view/friend_req_msg.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{msgTime(msg)}}
4 | ×
5 |
6 |
{{msg.content.friend_name}} wants to be your friend.
7 |
8 | Accept
9 | Decline
10 | Block
11 |
12 |
--------------------------------------------------------------------------------
/webclient/editor/fragments/aliases.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Aliases
4 | New
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/webclient/editor/js/admin.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').controller('MainAdminCtrl', ['$scope', 'lpRemote', 'lpUtil',
2 | function($scope, lpRemote, lpUtil) {
3 |
4 | lpRemote.request('admin/operations', {name: 'list'}).then(function(operations) {
5 | lpUtil.stringSort(operations, 'name');
6 | $scope.operations = operations;
7 | });
8 |
9 | $scope.blanks = function(op) {
10 | var blanks = [];
11 | for (var ix = 0; ix < 4 - op.args.length; ix++) {
12 | blanks.push(ix);
13 | }
14 | return blanks;
15 | };
16 |
17 | $scope.executeOp = function(op) {
18 | lpRemote.request('admin/operations', op).then(function(result) {
19 | $scope.operationResult = result ? result : 'No Content';
20 | })
21 | };
22 |
23 | }]);
24 |
--------------------------------------------------------------------------------
/webclient/editor/fragments/script_list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Scripts
({{model.script_refs.length}})
5 |
6 |
7 |
8 | {{script.script}}
9 | {{script.func_name}}
10 | {{script.builder}}
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/webclient/editor/js/editor_filters.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').service('lpEditFilters', [function() {
2 |
3 | this.hasChild = function (filterType) {
4 | return function (items) {
5 | var result = [];
6 | angular.forEach(items, function (item) {
7 | if (item[filterType + "_list"].length) {
8 | result.push(item);
9 | }
10 | });
11 | return result;
12 | }
13 | }
14 | }]);
15 |
16 | angular.module('lampost_editor').filter('immTitle', ['lpUtil', 'lpEditor', function(lpUtil, lpEditor) {
17 |
18 | var map = {};
19 | angular.forEach(lpEditor.constants.imm_levels, function(level, title) {
20 | map[level] = lpUtil.capitalize(title);
21 | });
22 |
23 | return function(model) {
24 | return map[model.imm_level];
25 | }
26 | }]);
27 |
--------------------------------------------------------------------------------
/webclient/editor/panels/shadow_script.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Object Type
5 |
8 |
9 |
10 |
11 |
12 | Function
13 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/lampost_setup.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from lampost.util import logging
4 | from lampost.setup import startargs
5 |
6 | if __name__ != "__main__":
7 | print("Invalid usage")
8 | sys.exit(2)
9 |
10 |
11 | args = startargs.create_parser.parse_args()
12 |
13 | # We set the logging configuration before importing other modules so that the root logger is properly configured
14 | logging.init_config(args)
15 | logging.root_logger.info("Started with args {}", args)
16 |
17 | from lampost.di.resource import register
18 | register('log', logging.LogFactory())
19 |
20 | from lampost.setup import newsetup
21 |
22 | if args.flush:
23 | response = input("Please confirm the database number you wish to clear: ")
24 | if response != str(args.db_num):
25 | print("Database numbers do not match")
26 | sys.exit(2)
27 |
28 | newsetup.new_setup(args)
29 |
--------------------------------------------------------------------------------
/webclient/editor/js/imports_editor.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').controller('ImportsEditorCtrl', ['$scope', 'lpUtil', 'lpDialog', function($scope, lpUtil, lpDialog) {
2 |
3 |
4 | $scope.setDatabaseDialog = function() {
5 | lpDialog.show({templateUrl: "editor/dialogs/select_db.html" , controller: "DbSelectorCtrl",
6 | scope: $scope});
7 | }
8 | }]);
9 |
10 |
11 | angular.module('lampost_editor').controller('DbSelectorCtrl', ['$scope', 'lpRemote', function($scope, lpRemote) {
12 | $scope.newParams = {db_port: 6379, db_num:0, db_pw: null};
13 | if ($scope.dbParams) {
14 | angular.copy($scope.dbParams, $scope.newParams);
15 | }
16 |
17 | $scope.setDatabase = function() {
18 | lpRemote.request("editor/imports/set_db", $scope.newParams).then(function(newParams) {
19 | $scope.dbParams = newParams;
20 | $scope.dismiss();
21 | })
22 | }
23 | }]);
24 |
--------------------------------------------------------------------------------
/lampmud/editor/imports.py:
--------------------------------------------------------------------------------
1 | from lampost.server.handlers import MethodHandler
2 | from lampost.di.app import on_app_start
3 | from lampost.di.resource import Injected, module_inject
4 | from lampost.db.redisstore import RedisStore
5 |
6 | log = Injected('log')
7 | perm = Injected('perm')
8 | ev = Injected('dispatcher')
9 | module_inject(__name__)
10 |
11 | copy_dbs = {}
12 |
13 |
14 | @on_app_start
15 | def _start():
16 | ev.register('session_disconnect', _remove_db)
17 |
18 |
19 | def _remove_db(session):
20 | if session in copy_dbs:
21 | del copy_dbs[session]
22 |
23 |
24 | class ImportsEditor(MethodHandler):
25 |
26 | def set_db(self):
27 | perm.check_perm(self.player, 'admin')
28 | content = self._content()
29 | db = RedisStore(content.db_host, content.db_port, content.db_num, content.db_pw)
30 | copy_dbs[self.session] = db
31 | del content.db_pw
32 | return content.__dict__
33 |
--------------------------------------------------------------------------------
/webclient/editor/view/input_list.html:
--------------------------------------------------------------------------------
1 |
2 |
{{inputList.name}}
3 |
4 |
11 |
12 |
13 |
14 | Add
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/lampmud/lpmud/archetype.py:
--------------------------------------------------------------------------------
1 | from lampost.di.config import config_value
2 | from lampost.db.dbo import KeyDBO, OwnerDBO
3 | from lampost.db.dbofield import DBOField, DBOLField
4 |
5 |
6 | class Archetype(OwnerDBO, KeyDBO):
7 | dbo_key_type = 'archetype'
8 | dbo_set_key = 'archetypes'
9 |
10 | name = DBOField("Unnamed")
11 | desc = DBOField('')
12 | base_attrs = DBOField({})
13 |
14 |
15 | class PlayerRace(Archetype):
16 | dbo_key_type = "race"
17 | dbo_set_key = "races"
18 |
19 | default_skills = DBOField([], 'default_skill')
20 | start_room = DBOLField(dbo_class_id='room')
21 | start_instanced = DBOField(False)
22 |
23 | @classmethod
24 | def new_dto(cls):
25 | dto = super().new_dto()
26 | dto['start_room'] = config_value('default_start_room')
27 | base_val = config_value('base_attr_value')
28 | dto['base_attrs'] = {attr['dbo_id']: base_val for attr in config_value('attributes')}
29 | return dto
30 |
31 |
32 |
--------------------------------------------------------------------------------
/webclient/editor/panels/modify_exit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Modify {{cap(dirMap[activeExit.direction].name)}} Exit x
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Guarded
13 |
14 |
15 |
16 |
17 |
18 |
19 | Delete Exit
20 | Close
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/webclient/editor/view/imports.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Database Import
9 |
Set Database
10 |
11 |
12 |
13 |
14 |
15 | No Database Selected
16 |
17 |
18 | DB Host
19 | {{dbParams.db_host}}
20 | DB Port
21 | {{dbParams.db_host}}
22 | DB Number
23 | {{dbParams.db_num}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/lampmud/lpmud/newsetup.py:
--------------------------------------------------------------------------------
1 | from lampost.di.config import config_value
2 |
3 | from lampmud.lpmud.archetype import PlayerRace
4 | from lampmud.lpmud import attributes
5 |
6 |
7 | def first_time_setup(args, db):
8 | root_area = config_value('root_area_id')
9 | room_id = "{0}:0".format(root_area)
10 | imm_name = args.imm_name.lower()
11 |
12 | db.create_object('area', {'dbo_id': root_area, 'name': root_area, 'next_room_id': 1})
13 | db.create_object('room', {'dbo_id': room_id, 'title': "Immortal Start Room", 'desc': "A brand new start room for immortals."})
14 |
15 | attributes.init()
16 |
17 | race_dto = PlayerRace.new_dto()
18 | race_dto.update(config_value('default_player_race'))
19 | race = db.create_object(PlayerRace, race_dto)
20 |
21 | supreme_level = config_value('imm_levels')['supreme']
22 | player = db.create_object('player', {'dbo_id': imm_name, 'room_id': room_id, 'race': race.dbo_id, 'home_room': room_id, 'imm_level': supreme_level})
23 | db.save_object(player)
24 | return player
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/webclient/mud/view/status_tab.html:
--------------------------------------------------------------------------------
1 |
25 |
--------------------------------------------------------------------------------
/webclient/mud/dialogs/select_character.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
Character Name
13 |
14 |
15 |
16 |
17 |
18 |
{{player.name}}
19 |
20 |
21 | Play
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/lampmud/model/mobile.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbo import CoreDBO, ChildDBO
2 | from lampost.db.dbofield import DBOField
3 | from lampost.db.template import Template
4 |
5 | from lampmud.model.entity import Entity
6 | from lampmud.model.item import target_keys, ItemInstance
7 |
8 |
9 | class MobileTemplate(ChildDBO, Template):
10 | dbo_key_type = 'mobile'
11 | dbo_parent_type = 'area'
12 |
13 | def _on_loaded(self):
14 | self.target_keys = target_keys(self)
15 |
16 | def config_instance(self, instance, room):
17 | instance.attach()
18 | instance.original_env = room
19 | room.mobiles[self].add(instance)
20 | instance.enter_env(room)
21 |
22 |
23 | class Mobile(Entity, ItemInstance):
24 | template_id = 'mobile'
25 |
26 | def _on_detach(self):
27 | self.original_env.mobiles[self.template].remove(self)
28 |
29 |
30 | class MobileReset(CoreDBO):
31 | class_id = 'mobile_reset'
32 | mobile = DBOField(dbo_class_id='mobile', required=True)
33 | reset_key = DBOField(0)
34 | reset_count = DBOField(1)
35 | reset_max = DBOField(1)
36 |
--------------------------------------------------------------------------------
/webclient/editor/view/simple_list.html:
--------------------------------------------------------------------------------
1 |
2 |
{{valueSet.name}}
3 |
4 |
5 |
6 |
7 |
8 | {{row}}
9 |
11 |
12 |
13 |
14 |
15 |
16 |
18 | Add
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/webclient/common/dialogs/prompt.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webclient/editor/view/option_list.html:
--------------------------------------------------------------------------------
1 |
2 |
{{valueSet.name}}
3 |
17 |
18 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Geoffrey D Genz and other contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/webclient/editor/panels/feature.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Add Room Feature x
5 |
6 |
7 |
8 |
9 |
10 |
11 | Feature Type
12 |
13 | -- Select --
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Add {{cap(newFeature.class_id)}}
22 | Cancel
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/webclient/editor/dialogs/script_selector.html:
--------------------------------------------------------------------------------
1 |
31 |
--------------------------------------------------------------------------------
/webclient/editor/dialogs/select_db.html:
--------------------------------------------------------------------------------
1 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/lampmud/lpmud/feature/touchstone.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbofield import DBOField
2 | from lampost.gameops.action import obj_action
3 | from lampmud.model.item import Readable, ItemDBO
4 |
5 |
6 | class Inscription(ItemDBO, Readable):
7 | class_id = 'inscription'
8 |
9 | inscription = Inscription()
10 | inscription.title = "Archaic Inscription"
11 | inscription.text = "Herewith wilt thou be bound"
12 | inscription.desc = "An inscription written in the flowery letters of a time long past."
13 | inscription.on_loaded()
14 |
15 |
16 | class Touchstone(ItemDBO):
17 | class_id = 'touchstone'
18 |
19 | title = DBOField('Touchstone')
20 | desc = DBOField("An unadorned marble obelisk about five feet high. There is an inscription in an archaic script on one side.")
21 | aliases = DBOField(["obelisk"])
22 | inscription = DBOField(inscription, 'inscription')
23 |
24 | @obj_action()
25 | def touch(self, source, **_):
26 | source.display_line("You feel a shock coursing through you. It lasts a few seconds")
27 | source.touchstone = self.dbo_owner.dbo_id
28 |
29 | def _on_loaded(self):
30 | self.target_providers = [self.inscription]
31 | self.instance_providers.append(self.inscription)
32 |
--------------------------------------------------------------------------------
/webclient/editor/view/edit_list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{editorLabel()}}:
{{editorTitle()}}
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {{col.header}}
15 |
16 |
17 |
18 |
19 | {{col.data(model)}}
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/webclient/editor/panels/modify_script.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Modify Shadow Script x
4 |
5 |
6 |
7 |
8 |
14 |
15 |
16 | Priority
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Delete Script
25 |
26 | Cancel
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/lampmud/editor/shared.py:
--------------------------------------------------------------------------------
1 | from lampost.di.resource import Injected, module_inject
2 | from lampost.db.exceptions import DataError
3 | from lampost.editor.editor import Editor
4 | from lampmud.comm.broadcast import BroadcastMap, Broadcast, broadcast_types
5 |
6 | mud_actions = Injected('mud_actions')
7 | module_inject(__name__)
8 |
9 |
10 | class SocialsEditor(Editor):
11 | def __init__(self):
12 | super().__init__('social')
13 |
14 | @staticmethod
15 | def preview(source, target, b_map, self_source, **_):
16 | broadcast = Broadcast(BroadcastMap(**b_map), source, source if self_source else target)
17 | return {broadcast_type['id']: broadcast.substitute(broadcast_type['id']) for broadcast_type in broadcast_types}
18 |
19 | def _pre_create(self, obj_def, *_):
20 | if mud_actions.primary(obj_def['dbo_id']):
21 | raise DataError("Verb already in use")
22 |
23 |
24 | def _ensure_name(obj_def):
25 | name = obj_def['name'] or obj_def['verb'] or obj_def['dbo_id']
26 | obj_def['name'] = name.capitalize()
27 |
28 |
29 | class SkillEditor(Editor):
30 | def _pre_create(self, obj_def, *_):
31 | _ensure_name(obj_def)
32 |
33 | def _pre_update(self, obj_def, *_):
34 | _ensure_name(obj_def)
35 |
36 |
--------------------------------------------------------------------------------
/lampmud/env/instancemgr.py:
--------------------------------------------------------------------------------
1 | from lampost.di.app import on_app_start
2 | from lampost.di.config import ConfigVal
3 | from lampost.di.resource import Injected, module_inject
4 |
5 | from lampmud.env.instance import AreaInstance
6 |
7 | db = Injected('datastore')
8 | ev = Injected('dispatcher')
9 | module_inject(__name__)
10 |
11 | preserve_hours = ConfigVal('instance_preserve_hours')
12 |
13 | instance_map = {}
14 |
15 |
16 | @on_app_start
17 | def _start():
18 | ev.register('maintenance', remove_old)
19 |
20 |
21 | def next_instance():
22 | instance_id = db.db_counter('instance_id')
23 | area_instance = AreaInstance(instance_id)
24 | instance_map[instance_id] = area_instance
25 | return area_instance
26 |
27 |
28 | def remove_old():
29 | stale_pulse = ev.future_pulse(preserve_hours.value * 60 * 60)
30 | for instance_id, instance in instance_map.copy().items():
31 | if instance.pulse_stamp < stale_pulse and not [entity for entity in instance.entities
32 | if hasattr(entity, 'is_player') and entity.session]:
33 | delete(instance_id)
34 |
35 |
36 | def get(instance_id):
37 | return instance_map.get(instance_id)
38 |
39 |
40 | def delete(instance_id):
41 | del instance_map[instance_id]
42 |
--------------------------------------------------------------------------------
/webclient/editor/view/value_set.html:
--------------------------------------------------------------------------------
1 |
2 |
{{valueSet.name}}
3 |
4 |
5 |
7 | {{valueSet.rowLabel(row)}}
8 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
19 | Add
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/lampmud/env/movement.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbo import CoreDBO
2 |
3 |
4 | class Direction(CoreDBO):
5 | class_id = 'direction'
6 | ref_map = {}
7 | ordered = []
8 |
9 | @classmethod
10 | def load_ref(cls, dbo_id, owner=None):
11 | return cls.ref_map[dbo_id] if dbo_id else None
12 |
13 | @classmethod
14 | def find_dir(cls, name):
15 | for key, value in cls.ref_map.items():
16 | if name == key or name == value.desc:
17 | return value
18 |
19 | def __init__(self, dbo_id, desc, rev_key):
20 | self.dbo_id = dbo_id
21 | self.desc = desc
22 | self.rev_key = rev_key
23 | Direction.ref_map[dbo_id] = self
24 | Direction.ordered.append({'dbo_id':dbo_id, 'name':desc, 'rev_key': rev_key})
25 |
26 | @property
27 | def rev_dir(self):
28 | return Direction.ref_map[self.rev_key]
29 |
30 |
31 | NORTH = Direction('n', 'north', 's')
32 | SOUTH = Direction('s', 'south', 'n')
33 | EAST = Direction('e', 'east', 'w')
34 | WEST = Direction('w', 'west', 'e')
35 | UP = Direction('u', 'up', "d")
36 | DOWN = Direction('d', 'down', "u")
37 | NE = Direction('ne', 'northeast', 'sw')
38 | SE = Direction('se', 'southeast', 'nw')
39 | NW = Direction('nw', 'northwest', 'se')
40 | SW = Direction('sw', 'southwest', 'ne')
41 |
--------------------------------------------------------------------------------
/webclient/editor/view/editor_main.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webclient/mud/dialogs/password_reset.html:
--------------------------------------------------------------------------------
1 |
35 |
--------------------------------------------------------------------------------
/webclient/mud/dialogs/forgot_password.html:
--------------------------------------------------------------------------------
1 |
31 |
--------------------------------------------------------------------------------
/webclient/mud/dialogs/forgot_name.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webclient/mud/js/status.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_mud').controller('StatusTabCtrl', ['$scope', 'lpData', 'lpEvent',
2 | function($scope, lpData, lpEvent) {
3 |
4 | $scope.statsList = ['health', 'mental', 'stamina', 'action'];
5 | $scope.stats = {action: {label: 'Action'},
6 | health: {label: 'Health'},
7 | stamina: {label: 'Stamina'},
8 | mental: {label: 'Mental'}};
9 | $scope.oppStats = angular.copy($scope.stats);
10 |
11 | updateStatus(lpData.status);
12 |
13 | lpEvent.register('status', updateStatus, $scope);
14 |
15 | function updateStatus(status) {
16 | $scope.status = status;
17 | updateBars($scope.stats, status);
18 | $scope.opponent = status.opponent;
19 | if ($scope.opponent) {
20 | updateBars($scope.oppStats, $scope.opponent);
21 | }
22 | }
23 |
24 | function updateBars(barStats, rawStats) {
25 | angular.forEach($scope.statsList, function(key) {
26 | var stats = barStats[key];
27 | var perc = Math.ceil(100 * rawStats[key] / rawStats['base_' + key]).toString();
28 | stats.style = {width: perc.toString() + '%'};
29 | if (perc < 20) {
30 | stats.class = 'progress-bar-danger';
31 | } else if (perc < 50) {
32 | stats.class = 'progress-bar-warning';
33 | } else {
34 | stats.class = 'progress-bar-success';
35 | }
36 | });
37 | }
38 |
39 | }]);
40 |
--------------------------------------------------------------------------------
/lampmud/server/messages.py:
--------------------------------------------------------------------------------
1 | from lampost.di.resource import Injected, module_inject
2 | from lampost.server.link import link_route
3 |
4 | um = Injected('user_manager')
5 | friend_service = Injected('friend_service')
6 | message_service = Injected('message_service')
7 | module_inject(__name__)
8 |
9 |
10 | @link_route('messages/friend_response')
11 | def friend_response(source_id, player_id, action, msg_id, **_):
12 | friend_service.remove_request(source_id, player_id)
13 | message_service.remove_message(player_id, msg_id)
14 | if action == 'accept':
15 | friend_service.add_friend(source_id, player_id)
16 | message_service.add_message("system", "{} has accepted your friend request.".format(um.id_to_name(player_id)), source_id)
17 | message_service.add_message("system", "You have accepted {}'s friend request.".format(um.id_to_name(source_id)), player_id)
18 | elif action == 'block':
19 | message_service.block_messages(player_id, source_id)
20 | else:
21 | message_service.add_message("system", "{} has declined your friend request.".format(um.id_to_name(player_id)), source_id)
22 | message_service.add_message("system", "You have declined {}'s friend request.".format(um.id_to_name(source_id)), player_id)
23 |
24 |
25 | @link_route('messages/delete')
26 | def message_delete(player_id, msg_id, **_):
27 | message_service.remove_message(player_id, msg_id)
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/lampmud/mud/inventory.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbofield import DBOField
2 |
3 | from lampmud.model.item import ItemDBO
4 | from lampmud.mud.action import mud_action
5 |
6 |
7 | @mud_action(('get', 'pick up'), 'get', target_class="env_items", quantity=True)
8 | def get(source, target, quantity=None):
9 | target.get(source, quantity)
10 |
11 |
12 | @mud_action(('drop', 'put down'), 'drop', target_class="inven", quantity=True)
13 | def drop(source, target, quantity=None):
14 | target.drop(source, quantity)
15 |
16 |
17 | @mud_action(('i', 'inventory'))
18 | def inven(source):
19 | if source.inven:
20 | source.display_line("You are carrying:")
21 | for article in source.inven:
22 | source.display_line(" {}".format(article.short_desc(source)))
23 | else:
24 | source.display_line("You aren't carrying anything.")
25 |
26 |
27 | class InvenContainer(ItemDBO):
28 | class_id = 'container'
29 |
30 | contents = DBOField([], 'untyped')
31 |
32 | def __iter__(self):
33 | for item in self.contents:
34 | yield item
35 |
36 | def __len__(self):
37 | return len(self.contents)
38 |
39 | def __contains__(self, item):
40 | return item in self.contents
41 |
42 | def __getitem__(self, key):
43 | return self.contents[key]
44 |
45 | def append(self, item):
46 | self.contents.append(item)
47 |
48 | def remove(self, item):
49 | self.contents.remove(item)
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/lampmud/setup/update.py:
--------------------------------------------------------------------------------
1 | from lampost.di.resource import Injected, module_inject
2 | from lampost.editor.admin import admin_op
3 |
4 | log = Injected('log')
5 | db = Injected('datastore')
6 | ev = Injected('dispatcher')
7 | module_inject(__name__)
8 |
9 |
10 | @admin_op
11 | def assign_race(race_id):
12 | race = db.load_object(race_id, 'race')
13 | updates = 0
14 | if not race:
15 | return "Invalid race specified"
16 | for player in db.load_object_set('player'):
17 | if not player.race:
18 | log.info("Assigning race {} to {}", race_id, player.name)
19 | player.race = race
20 | db.save_object(player)
21 | updates += 1
22 | return "{} players updated.".format(updates)
23 |
24 |
25 | def test_memory(*_):
26 | for area_ix in range(1000):
27 | area_id = 'perf_test{}'.format(area_ix)
28 | old_area = db.load_object(area_id, 'area')
29 | if old_area:
30 | db.delete_object(old_area)
31 | area_dbo = {'dbo_id': area_id}
32 | db.create_object('area', area_dbo)
33 | for dbo_id in range(100):
34 | room = {'dbo_id': '{}:{}'.format(area_id, dbo_id), 'desc': area_id * 40, 'title': area_id * 2}
35 | db.create_object('room', room)
36 |
37 |
38 | def clean_perf(*_):
39 | for area_ix in range(1000):
40 | area_id = 'perf_test{}'.format(area_ix)
41 | old_area = db.load_object(area_id, 'area')
42 | if old_area:
43 | db.delete_object(old_area)
44 |
45 |
--------------------------------------------------------------------------------
/webclient/editor/panels/touchstone.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Modify Touchstone x
5 |
6 |
7 |
8 |
9 |
10 |
11 | Title
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Description
20 |
21 |
22 |
23 | Inscription
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Delete Touchstone
32 | Close
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/lampmud/mud/action.py:
--------------------------------------------------------------------------------
1 | from lampost.di.resource import Injected, module_inject, register
2 | from lampost.gameops.action import make_action, ActionError, ActionCache
3 |
4 | log = Injected('log')
5 | module_inject(__name__)
6 |
7 | _mud_actions = ActionCache()
8 | register('mud_actions', _mud_actions)
9 |
10 | imm_actions = set()
11 |
12 |
13 | def mud_action(verbs, msg_class=None, **kwargs):
14 | def dec_wrapper(func):
15 | action = make_action(func, verbs, msg_class, **kwargs)
16 | _mud_actions.add_unique(action)
17 | return dec_wrapper
18 |
19 |
20 | def imm_action(verbs, msg_class=None, imm_level='builder', **kwargs):
21 | def dec_wrapper(func):
22 | imm_actions.add(func)
23 | func.imm_level = imm_level
24 | return make_action(func, verbs, msg_class, **kwargs)
25 | return dec_wrapper
26 |
27 |
28 | @mud_action('help', target_class='cmd_str_opt')
29 | def help_action(source, target):
30 | if not target:
31 | source.display_line('Available actions:')
32 | verb_lists = ["/".join(verbs) for verbs in _mud_actions.all_actions().values()]
33 | return source.display_line(", ".join(sorted(verb_lists)))
34 | actions = _mud_actions.primary(target)
35 | if not actions:
36 | actions = _mud_actions.abbrev(target)
37 | if not actions:
38 | raise ActionError("No matching command found")
39 | if len(actions) > 1:
40 | raise ActionError("Multiple matching actions")
41 | return getattr(actions[0], "help_text", "No help available.")
42 |
--------------------------------------------------------------------------------
/webclient/editor/view/area.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Area Name
20 |
21 |
22 |
23 |
24 |
25 | Next Room
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Description
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/lampmud/lpmud/article.py:
--------------------------------------------------------------------------------
1 | from lampost.gameops.script import Scriptable
2 |
3 | from lampmud.comm.broadcast import BroadcastMap
4 | from lampost.meta.auto import TemplateField
5 | from lampost.db.dbofield import DBOField, DBOTField
6 | from lampmud.model.article import Article, ArticleTemplate
7 | from lampmud.mud.action import mud_action
8 |
9 |
10 | class ArticleTemplateLP(ArticleTemplate):
11 | class_id = 'article'
12 |
13 | remove_msg = BroadcastMap(s="You unequip {N}", e="{n} unequips {N}")
14 | equip_msg = BroadcastMap(s="You wear {N}", e="{n} wears {N}")
15 | wield_msg = BroadcastMap(s="You wield {N}", e="{n} wields {N}")
16 |
17 | def _on_loaded(self):
18 | if self.art_type == 'weapon':
19 | self.equip_msg = self.wield_msg
20 |
21 |
22 | class ArticleLP(Article, Scriptable):
23 | equip_slot = DBOTField()
24 | current_slot = DBOField()
25 |
26 | weapon_type = DBOTField('mace')
27 | damage_type = DBOTField('blunt')
28 | delivery = DBOTField('melee')
29 | equip_msg = TemplateField()
30 | remove_msg = TemplateField()
31 |
32 | def on_equipped(self, equipper):
33 | equipper.broadcast(target=self, broadcast_map=self.equip_msg)
34 |
35 | def on_removed(self, remover):
36 | remover.broadcast(target=self, broadcast_map=self.remove_msg)
37 |
38 |
39 | @mud_action(('wear', 'equip', 'wield'), 'equip_slot', target_class="inven")
40 | def wear(source, target, **_):
41 | source.equip_article(target)
42 |
43 |
44 | @mud_action(('remove', 'unequip', 'unwield'), 'current_slot')
45 | def remove(source, target, **_):
46 | source.remove_article(target)
47 |
--------------------------------------------------------------------------------
/webclient/editor/js/area_editor.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').controller('MobileEditorCtrl', ['$scope', 'lpEditorTypes', 'lpSkillService',
2 | function ($scope, lpEditorTypes, lpSkillService) {
3 |
4 | var skillSet = new lpEditorTypes.ValueObjList('default_skills', "Default Skills [Level]", 'skill_template', 'skill_level');
5 | skillSet.options = lpSkillService.allSkills();
6 | skillSet.optionKey = 'dbo_key';
7 | $scope.skillSet = skillSet;
8 |
9 | }]);
10 |
11 |
12 | angular.module('lampost_editor').controller('ArticleEditorCtrl', ['$scope', 'lpEvent', 'lpEditor',
13 | function ($scope, lpEvent, lpEditor) {
14 |
15 | $scope.locals = {};
16 | $scope.equip_slots = angular.copy($scope.constants.equip_slots);
17 | $scope.equip_slots.unshift('[none]');
18 | $scope.addPanel = null;
19 |
20 | $scope.syncSlot = function() {
21 | $scope.model.equip_slot = $scope.locals.equipSlot == '[none]' ? null : $scope.locals.equipSlot;
22 | };
23 |
24 | lpEvent.register('editReady', function() {
25 | $scope.locals.equipSlot = lpEditor.original.equip_slot ? lpEditor.original.equip_slot : '[none]';
26 | $scope.closeAdd();
27 | });
28 |
29 | $scope.addScript = function(event) {
30 | if (event) {
31 | event.stopImmediatePropagation();
32 | event.preventDefault();
33 | }
34 | $scope.addPanel = 'editor/panels/new_script.html';
35 | };
36 |
37 | $scope.modifyScript = function(scriptRef) {
38 | lpEditor.addObj = scriptRef;
39 | $scope.addPanel = 'editor/panels/modify_script.html';
40 | };
41 |
42 | $scope.closeAdd = function() {
43 | $scope.addPanel = null;
44 | }
45 |
46 |
47 | }]);
48 |
--------------------------------------------------------------------------------
/lampmud/lpmud/attributes.py:
--------------------------------------------------------------------------------
1 | from lampost.di.app import on_app_start
2 | from lampost.di.config import config_value
3 | from lampost.db.dbofield import DBOField
4 | from lampost.db.registry import get_dbo_class
5 |
6 | attributes = []
7 | attr_list = []
8 |
9 | pool_keys = []
10 | resource_pools = []
11 |
12 |
13 | @on_app_start(priority=200)
14 | def init():
15 | global attributes
16 | global resource_pools
17 | global pool_keys
18 | global attr_list
19 |
20 | attributes = config_value('attributes')
21 | attr_list = [attr['dbo_id'] for attr in attributes]
22 |
23 | resource_pools = config_value('resource_pools')
24 | pool_keys = [(pool['dbo_id'], "base_{}".format(pool['dbo_id'])) for pool in resource_pools]
25 |
26 | player_cls = get_dbo_class('player')
27 | player_cls.add_dbo_fields({attr['dbo_id']: DBOField(0) for attr in attributes})
28 | player_cls.add_dbo_fields({pool['dbo_id']: DBOField(0) for pool in resource_pools})
29 |
30 |
31 | def base_pools(entity):
32 | for pool in resource_pools:
33 | total = sum(getattr(entity, key) * value for key, value in pool['calc'].items())
34 | setattr(entity, 'base_{}'.format(pool['dbo_id']), total)
35 |
36 |
37 | def fill_pools(entity):
38 | base_pools(entity)
39 | for pool_id, base_pool_id in pool_keys:
40 | setattr(entity, pool_id, getattr(entity, base_pool_id))
41 |
42 |
43 | def restore_attrs(entity):
44 | for attr in attr_list:
45 | setattr(entity, attr, getattr(entity, "perm_{}".format(attr)))
46 |
47 |
48 | def need_refresh(entity):
49 | for pool_id, base_pool_id in pool_keys:
50 | if getattr(entity, pool_id) < getattr(entity, base_pool_id):
51 | return True
52 |
--------------------------------------------------------------------------------
/lampmud/mud/chat.py:
--------------------------------------------------------------------------------
1 | from lampost.gameops.action import ActionError
2 | from lampost.di.resource import Injected, module_inject
3 | from lampmud.mud.action import mud_action
4 |
5 | sm = Injected('session_manager')
6 | module_inject(__name__)
7 |
8 |
9 | @mud_action('emote', target_class='cmd_str')
10 | def emote(source, target):
11 | source.broadcast(raw="{}{} {}".format('' if source.imm_level else ':', source.name, target))
12 |
13 |
14 | @mud_action('tell', target_class="player_online", obj_class="cmd_str")
15 | def tell(source, target, obj):
16 | tell_message(source, target, obj)
17 |
18 |
19 | def tell_message(source, player, statement):
20 | if not statement:
21 | return source.display_line("Say what to " + player.name + "?")
22 | player.last_tell = source.dbo_id
23 | player.display_line(source.name + " tells you, `" + statement + "'", 'tell_from')
24 | source.display_line("You tell " + player.name + ", `" + statement + "'", 'tell_to')
25 |
26 |
27 | @mud_action('reply', target_class='cmd_str')
28 | def reply(source, target):
29 | if not source.last_tell:
30 | raise ActionError("You have not received a tell recently.")
31 | session = sm.player_session(source.last_tell)
32 | if session:
33 | tell_message(source, session.player, target)
34 | else:
35 | source.last_tell = None
36 | return source.display_line("{} is no longer logged in".format(source.last_tell))
37 |
38 |
39 | @mud_action('say', target_class='cmd_str')
40 | def say(source, target):
41 | source.display_line("You say, `{}'".format(target), display='say')
42 | source.broadcast(raw="{} says, `{}'".format(source.name, target),
43 | display='say', silent=True)
44 |
--------------------------------------------------------------------------------
/webclient/editor/view/admin_view.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Available Operations
6 |
7 |
27 |
28 |
29 | {{operationResult}}
30 |
31 |
Clear
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/lampmud/lpmud/combat/system.py:
--------------------------------------------------------------------------------
1 | import bisect
2 |
3 | from lampost.di.resource import Injected, module_inject
4 |
5 | ev = Injected('dispatcher')
6 | module_inject(__name__)
7 |
8 | _pulse_map = {}
9 |
10 |
11 | def add_action(source, action, pulse, callback, priority=0):
12 | if not pulse:
13 | process_immediate(source, action, callback)
14 | return
15 | pulse_key = ev.current_pulse + pulse
16 | current_diff = pulse
17 | sys_action = SystemAction(source, action, priority, callback)
18 |
19 | try:
20 | pulse_actions = _pulse_map[pulse_key]
21 | except KeyError:
22 | _pulse_map[pulse_key] = pulse_actions = []
23 | ev.register_once(process_actions, current_diff, kwargs={'pulse_key': pulse_key})
24 | bisect.insort_right(pulse_actions, sys_action)
25 |
26 |
27 | def process_actions(pulse_key):
28 | affected = set()
29 | actions = _pulse_map[pulse_key]
30 | for sys_action in actions:
31 | affected.add(sys_action.source)
32 | sys_action.callback(sys_action.action, affected)
33 | del _pulse_map[pulse_key]
34 | for entity in affected:
35 | try:
36 | entity.resolve_actions()
37 | except AttributeError:
38 | pass
39 |
40 |
41 | def process_immediate(source, action, callback):
42 | affected = {source}
43 | callback(action, affected)
44 | for entity in affected:
45 | try:
46 | entity.resolve_actions()
47 | except AttributeError:
48 | pass
49 |
50 |
51 | class SystemAction:
52 | def __init__(self, source, action, priority, callback):
53 | self.source = source
54 | self.action = action
55 | self.priority = priority
56 | self.callback = callback
57 |
58 | def __lt__(self, other):
59 | return self.priority < other.priority
60 |
--------------------------------------------------------------------------------
/lampmud/mud/socials.py:
--------------------------------------------------------------------------------
1 | from lampost.di.app import on_app_start
2 |
3 | from lampmud.comm.broadcast import BroadcastMap
4 | from lampost.di.resource import Injected, module_inject
5 | from lampost.db.dbo import KeyDBO, OwnerDBO
6 | from lampost.db.dbofield import DBOField
7 | from lampost.gameops.action import make_action
8 | from lampmud.mud.action import mud_action
9 |
10 | log = Injected('log')
11 | db = Injected('datastore')
12 | mud_actions = Injected('mud_actions')
13 | module_inject(__name__)
14 |
15 | all_socials = {}
16 |
17 |
18 | @on_app_start
19 | def _start():
20 | for social in db.load_object_set('social'):
21 | add_social_action(social)
22 |
23 |
24 | def add_social_action(social):
25 | if mud_actions.primary(social.dbo_id):
26 | log.warn("Mud action already exists for social id {}", social.dbo_id)
27 | else:
28 | mud_actions.add(make_action(social, social.dbo_id))
29 | all_socials[social.dbo_id] = social
30 |
31 |
32 | def remove_social_action(social):
33 | all_socials.pop(social.dbo_id)
34 | mud_actions.remove(social)
35 |
36 |
37 | class Social(KeyDBO, OwnerDBO):
38 | dbo_key_type = 'social'
39 | dbo_set_key = 'socials'
40 |
41 | b_map = DBOField({})
42 |
43 | msg_class = 'social'
44 |
45 | def _on_loaded(self):
46 | self.broadcast_map = BroadcastMap(**self.b_map)
47 |
48 | def _on_db_created(self):
49 | add_social_action(self)
50 |
51 | def _on_db_deleted(self):
52 | remove_social_action(self)
53 |
54 | def __call__(self, source, target, **_):
55 | source.broadcast(target=target, broadcast_map=self.broadcast_map)
56 |
57 |
58 | @mud_action('socials')
59 | def socials_action(**_):
60 | socials = sorted(all_socials.keys())
61 | if socials:
62 | return " ".join(socials)
63 | return "No socials created!"
64 |
--------------------------------------------------------------------------------
/lampmud/lpmud/env.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbofield import DBOField
2 | from lampost.di.app import on_app_start
3 | from lampost.gameops.action import ActionError
4 | from lampost.di.config import on_config_change, config_value
5 |
6 | from lampmud.env.room import Exit
7 |
8 | exit_cost_map = {}
9 | prep_multiplier = 1
10 |
11 |
12 | @on_app_start
13 | @on_config_change
14 | def _config():
15 | global room_stamina
16 | global room_action
17 | global default_room_size
18 | room_stamina = config_value('room_stamina')
19 | room_action = config_value('room_action')
20 | default_room_size = config_value('default_room_size')
21 |
22 |
23 | def find_cost(room):
24 | if room and room.size:
25 | try:
26 | return exit_cost_map[room.size]
27 | except KeyError:
28 | exit_cost_map[room.size] = {'action': int(room_stamina * room.size / default_room_size),
29 | 'stamina': int(room_action * room.size / default_room_size)}
30 | return exit_cost_map[room.size]
31 |
32 |
33 | class ExitLP(Exit):
34 | class_id = 'exit'
35 |
36 | guarded = DBOField(False)
37 | door_key = DBOField()
38 |
39 | @property
40 | def prep_time(self):
41 | return prep_multiplier * self.dbo_owner.size // 10
42 |
43 | def prepare_action(self, source):
44 | if self.guarded:
45 | guards = [guard for guard in source.env.denizens if guard.affinity != source.affinity]
46 | if guards:
47 | raise ActionError(guards[0].guard_msg.format(source=guards[0].name, exit=self._dir.desc))
48 | source.display_line("You head {}.".format(self._dir.desc))
49 | source.env.allow_leave(source, self)
50 |
51 | def _move_user(self, source):
52 | source.apply_costs(find_cost(self.dbo_owner))
53 | super()._move_user(source)
54 |
--------------------------------------------------------------------------------
/webclient/editor/js/player_editor.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').controller('PlayerEditorCtrl', ['$scope', 'lpCache', 'lpEditor', 'lpEvent', 'lpEditorTypes',
2 | function ($scope, lpCache, lpEditor, lpEvent, lpEditorTypes) {
3 |
4 | var prevLevel, model;
5 |
6 | function setPerms() {
7 | model = $scope.model;
8 | $scope.canPromote = model.can_write && lpEditor.playerId != model.dbo_id && lpEditor.immLevel >= lpEditor.constants.imm_levels.admin;
9 | prevLevel = $scope.model.imm_level;
10 | }
11 |
12 | $scope.checkPromote = function() {
13 | var error;
14 | if (model.logged_in == 'Yes') {
15 | error = "Please do that in game.";
16 | } else if (lpEditor.immLevel <= model.imm_level && lpEditor.immLevel < lpEditor.constants.imm_levels.supreme) {
17 | error = "You cannot promote to that level!"
18 | }
19 | if (error) {
20 | $scope.errors.promote = error;
21 | $scope.model.imm_level = prevLevel;
22 | } else {
23 | $scope.errors.promote = null;
24 | prevLevel = $scope.model.imm_level;
25 | }
26 | };
27 |
28 | lpCache.cache('race').then(function(races) {
29 | $scope.races = races;
30 | });
31 |
32 | $scope.$on('$destroy', function() {
33 | lpCache.deref('race');
34 | });
35 |
36 | lpEvent.register('editReady', setPerms);
37 |
38 | $scope.playerRoomSelect = new lpEditorTypes.ChildSelect('room_id', 'room');
39 |
40 | }]);
41 |
42 |
43 | angular.module('lampost_editor').controller('UserEditorCtrl', ['$scope', 'lpEvent', 'lpEditor', 'lpCache',
44 | function ($scope, lpEvent, lpEditor, lpCache) {
45 |
46 | $scope.editPlayer = function(player_id) {
47 | var playerModel = lpCache.cachedValue('player:' + player_id);
48 | if (playerModel) {
49 | lpEvent.dispatchLater('startEdit', playerModel);
50 | }
51 | }
52 |
53 | }]);
54 |
--------------------------------------------------------------------------------
/webclient/editor/panels/extra.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{newAdd ? 'Create': 'Modify'}} Extra x
4 |
5 |
6 |
7 |
8 |
9 | Title
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Description
21 |
22 |
23 |
24 |
25 |
26 |
27 | ×
28 | {{lastError}}
29 |
30 |
31 |
32 |
33 |
34 | Delete Extra
36 |
37 | Add {{addLabel}}
39 |
40 | {{newAdd ? 'Cancel' : 'Close'}}
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/webclient/editor/view/script.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
19 |
20 |
21 | Script Title
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Approved
30 |
31 |
32 |
33 |
34 |
35 | Script Type
36 |
39 | Select Type
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/lampmud/editor/scripts.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 |
3 | from lampost.editor.editor import ChildrenEditor
4 |
5 | from lampost.di.resource import Injected, module_inject
6 | from lampost.db.exceptions import DataError
7 | from lampost.gameops.script import compile_script
8 |
9 | db = Injected('datastore')
10 | perm = Injected('perm')
11 | module_inject(__name__)
12 |
13 |
14 | def _validate(obj_def):
15 | hasher = hashlib.md5()
16 | hasher.update(obj_def['text'].encode())
17 | obj_def['script_hash'] = hasher.hexdigest()
18 | _, err_str = compile_script(obj_def['script_hash'], obj_def['text'], obj_def['title'])
19 | if err_str:
20 | raise DataError(err_str)
21 |
22 |
23 | class ScriptEditor(ChildrenEditor):
24 | def __init__(self):
25 | super().__init__('script')
26 |
27 | def _pre_create(self, obj_def, session):
28 | _validate(obj_def)
29 | obj_def['approved'] = perm.has_perm(session.player, 'admin') and obj_def['approved']
30 |
31 | def _pre_update(self, obj_def, existing, session):
32 | _validate(obj_def)
33 | holder_keys = db.fetch_set_keys('{}:holders'.format(existing.dbo_key))
34 | if obj_def['builder'] == 'shadow':
35 | cls_type = obj_def['metadata']['cls_type']
36 | cls_shadow = obj_def['metadata']['cls_shadow']
37 | errors = []
38 | for dbo_key in holder_keys:
39 | holder = db.load_object(dbo_key)
40 | for script_ref in getattr(holder, "script_refs", ()):
41 | if script_ref.script.dbo_id == existing.dbo_id:
42 | if cls_type != holder.class_id:
43 | errors.append("{} wrong class id {}".format(holder.dbo_id, holder.class_id))
44 | elif script_ref.func_name != cls_shadow:
45 | errors.append("{} wrong function {}".format(holder.dbo_id, script_ref.func_name))
46 | if errors:
47 | raise DataError("Incompatible usages must be removed first: {}".format(" ".join(errors)))
48 | if obj_def['script_hash'] != existing.script_hash:
49 | obj_def['approved'] = perm.has_perm(session.player, 'admin') and obj_def['approved']
50 |
51 |
--------------------------------------------------------------------------------
/lampmud/model/item.py:
--------------------------------------------------------------------------------
1 | from lampost.event.zone import Attachable
2 | from lampost.gameops.target import TargetKeys
3 | from lampost.meta.auto import TemplateField
4 | from lampost.db.dbo import CoreDBO, DBOAspect
5 | from lampost.db.dbofield import DBOField, DBOTField
6 | from lampost.db.template import TemplateInstance
7 | from lampost.gameops.action import obj_action, ActionProvider
8 |
9 |
10 | def target_keys(item):
11 | t_keys = TargetKeys(item.title)
12 | for alias in item.aliases:
13 | t_keys.add(alias)
14 | return t_keys
15 |
16 |
17 | class ItemAspect(DBOAspect, ActionProvider, Attachable):
18 | sex = DBOField('none')
19 | flags = DBOField({})
20 | title = ''
21 | aliases = []
22 |
23 | living = False
24 | env = None
25 |
26 | def _on_loaded(self):
27 | if not self.target_keys:
28 | self.target_keys = target_keys(self)
29 |
30 | @property
31 | def name(self):
32 | return self.title
33 |
34 | def short_desc(self, observer=None):
35 | return self.title
36 |
37 | def long_desc(self, observer):
38 | return self.desc if self.desc else self.title
39 |
40 | def examine(self, source):
41 | if source.can_see(self):
42 | source.display_line(self.long_desc(source))
43 |
44 | def glance(self, source):
45 | if source.can_see(self):
46 | source.display_line(self.short_desc(source))
47 |
48 | def receive_broadcast(self, broadcast):
49 | pass
50 |
51 | def social(self, social):
52 | pass
53 |
54 | def leave_env(self):
55 | pass
56 |
57 |
58 | class ItemDBO(CoreDBO, ItemAspect):
59 | class_id = 'base_item'
60 |
61 | desc = DBOField('')
62 | title = DBOField('')
63 | aliases = DBOField([])
64 |
65 | target_keys = None
66 |
67 |
68 | class ItemInstance(TemplateInstance, ItemAspect):
69 | desc = DBOTField('')
70 | title = DBOTField('')
71 | aliases = DBOTField([])
72 |
73 | target_keys = TemplateField()
74 |
75 |
76 | class Readable(DBOAspect, ActionProvider):
77 | class_id = 'readable'
78 |
79 | text = DBOField('')
80 |
81 | @obj_action()
82 | def read(self, source):
83 | source.display_line(self.text, "tell_to")
84 |
--------------------------------------------------------------------------------
/webclient/editor/view/user.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Account Name
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Email
24 |
25 |
26 |
27 |
28 |
29 | New Password
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Password Reset
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | Players ({{model.player_ids.length}})
51 |
52 |
53 |
54 | {{cap(playerId)}}
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/webclient/editor/js/socials_editor.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').controller('SocialEditorCtrl', ['$scope', 'lpRemote', 'lpEditor', 'lpEvent',
2 | function ($scope, lpRemote, lpEditor, lpEvent) {
3 |
4 | var preview = {};
5 | var bTypeIds = [];
6 | var sourceSelf = false;
7 |
8 | $scope.bTypeGrid = [];
9 |
10 | angular.forEach(lpEditor.constants.broadcast_types, function (bType) {
11 | $scope.bTypeGrid[bType.grid_x] = $scope.bTypeGrid[bType.grid_x] || [];
12 | $scope.bTypeGrid[bType.grid_x][bType.grid_y] = bType;
13 | bTypeIds.push(bType.id);
14 | });
15 |
16 | $scope.editMode = true;
17 | $scope.source = 'Player';
18 | $scope.target = 'Target';
19 | $scope.displayMap = {};
20 |
21 | $scope.startEditMode = function () {
22 | $scope.editMode = true;
23 | updateDisplayMap();
24 | };
25 |
26 | $scope.toggleTarget = function () {
27 | sourceSelf = !sourceSelf;
28 | $scope.targetTitle = sourceSelf ? "Target is self." : 'Target is other.';
29 | $scope.targetClass = 'fa ' + (sourceSelf ? 'fa-reply-all' : 'fa-long-arrow-right')
30 | };
31 |
32 | $scope.previewSocial = function () {
33 | lpRemote.request('editor/social/preview', {
34 | target: $scope.target, self_source: sourceSelf,
35 | source: $scope.source, b_map: $scope.model.b_map
36 | }).then(function (data) {
37 | preview = data;
38 | preview.dbo_id = $scope.model.dbo_id;
39 | $scope.editMode = false;
40 | updateDisplayMap();
41 | });
42 | };
43 |
44 | $scope.updateSocial = function (bType) {
45 | $scope.model.b_map[bType] = $scope.displayMap[bType];
46 | };
47 |
48 | function updateDisplayMap() {
49 | if ($scope.model.b_map) {
50 | angular.forEach(bTypeIds, function (key) {
51 | $scope.displayMap[key] = $scope.editMode ? $scope.model.b_map[key] : preview[key];
52 | });
53 | }
54 | }
55 |
56 | lpEvent.register('editReady', function () {
57 | if (!$scope.editMode && $scope.model.dbo_id != preview.dbo_id) {
58 | $scope.previewSocial()
59 | } else {
60 | updateDisplayMap()
61 | }
62 | }, $scope);
63 |
64 | updateDisplayMap();
65 | $scope.toggleTarget();
66 |
67 | }]);
68 |
69 |
--------------------------------------------------------------------------------
/webclient/editor/view/mobile.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
22 |
23 |
24 | Title
25 |
26 |
27 |
28 |
29 |
30 |
31 | Level
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Description
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | Affinity
49 |
51 |
52 |
53 |
56 |
57 |
--------------------------------------------------------------------------------
/webclient/editor/panels/new_script.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Add User Script x
4 |
5 |
6 |
7 |
8 |
9 | Script
10 |
12 | Select Script
13 |
14 |
15 |
16 |
17 |
18 | Source Area
19 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
38 |
39 |
40 | Priority
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | Add Script
49 |
50 | Cancel
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/lampmud/mud/target.py:
--------------------------------------------------------------------------------
1 | from lampost.gameops.target import target_gen, recursive_targets, make_gen
2 |
3 |
4 | @target_gen
5 | def equip(key_type, target_key, entity, *_):
6 | return recursive_targets(key_type, [equip for equip in entity.inven if getattr(equip, 'current_slot', None)], target_key)
7 | equip.absent_msg = "You don't have `{target}' equipped."
8 |
9 |
10 | @target_gen
11 | def inven(key_type, target_key, entity, *_):
12 | return recursive_targets(key_type, [equip for equip in entity.inven if not getattr(equip, 'current_slot', None)],
13 | target_key)
14 | inven.absent_msg = "You don't have `{target}'."
15 |
16 |
17 | @target_gen
18 | def env(key_type, target_key, entity, *_):
19 | for extra in entity.env.extras:
20 | try:
21 | if target_key in getattr(extra.target_keys, key_type):
22 | yield extra
23 | except AttributeError:
24 | pass
25 | for target in recursive_targets(key_type, getattr(extra, 'target_providers', ()), target_key):
26 | yield target
27 |
28 |
29 | @target_gen
30 | def feature(key_type, target_key, entity, *_):
31 | return recursive_targets(key_type, (feature for feature in entity.env.features), target_key)
32 |
33 |
34 | @target_gen
35 | def env_living(key_type, target_key, entity, *_):
36 | return recursive_targets(key_type, (living for living in entity.env.denizens), target_key)
37 |
38 |
39 | @target_gen
40 | def player_env(key_type, target_key, entity, *_):
41 | return recursive_targets(key_type, (denizen for denizen in entity.env.denizens if getattr(denizen, 'is_player', False) and denizen != entity), target_key)
42 |
43 |
44 | @target_gen
45 | def env_items(key_type, target_key, entity, *_):
46 | return recursive_targets(key_type, [item for item in entity.env.inven], target_key)
47 |
48 |
49 | @target_gen
50 | def env_default(key_type, target_key, entity, *_):
51 | if not target_key:
52 | yield entity.env
53 |
54 |
55 | @target_gen
56 | def self_default(key_type, target_key, entity, *_):
57 | if not target_key:
58 | yield entity
59 |
60 |
61 | make_gen('self feature env_living env_items equip inven env_default', 'default')
62 |
63 | make_gen('self env_living self_default', 'living')
64 |
65 | make_gen('feature env_living env_items inven equip', '__invalid__')
66 |
--------------------------------------------------------------------------------
/webclient/mud/js/character.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_mud').controller('NewCharacterCtrl', ['$scope', 'lpData', 'lpRemote', 'lpEvent', 'lpDialog',
2 | function ($scope, lpData, lpRemote, lpEvent, lpDialog) {
3 |
4 | $scope.playerName = '';
5 | $scope.errorText = null;
6 | $scope.activeScreen = 'race';
7 | $scope.playerData = {};
8 |
9 | lpRemote.request("new_char_data").then(function (newCharData) {
10 | $scope.races = newCharData.races;
11 | $scope.ready = true;
12 | });
13 |
14 | $scope.tryCancel = function () {
15 | if (lpData.playerIds.length == 0) {
16 | lpDialog.showConfirm("No Characters", "This account has no characters and will be deleted. Do you still wish to continue?").then(
17 | function () {
18 | lpRemote.request("settings/delete_account").then(function (response) {
19 | lpEvent.dispatchMap(response);
20 | });
21 | $scope.dismiss();
22 | });
23 | } else {
24 | $scope.dismiss();
25 | }
26 | };
27 |
28 | $scope.createCharacter = function () {
29 | if ($scope.playerName.indexOf(" ") > -1) {
30 | $scope.errorText = "Spaces not permitted in character names";
31 | return;
32 | }
33 | lpRemote.request("settings/create_player", {user_id: lpData.userId, player_name: $scope.playerName, player_data: $scope.playerData})
34 | .then(function () {
35 | if (!lpData.playerId) {
36 | lpRemote.send('player_login', {player_id: $scope.playerName.toLowerCase()});
37 | }
38 | lpEvent.dispatch('players_updated');
39 | $scope.dismiss();
40 | }, function (error) {
41 | $scope.errorText = error.text;
42 | });
43 | };
44 |
45 | }]);
46 |
47 | angular.module('lampost_mud').controller('SelectCharacterCtrl', ['$scope', 'lpRemote', 'lpEvent', 'lpData',
48 | function ($scope, lpRemote, lpEvent, lpData) {
49 |
50 | $scope.players = [];
51 |
52 | $scope.selectCharacter = function (playerId) {
53 | lpRemote.send('player_login', {player_id: playerId});
54 | };
55 |
56 | lpEvent.register('login', $scope.dismiss, $scope);
57 |
58 | loadCharacters();
59 | function loadCharacters() {
60 | lpRemote.request("settings/get_players", {user_id: lpData.userId}).then(function (players) {
61 | $scope.players = players;
62 | });
63 | }
64 | }]);
65 |
--------------------------------------------------------------------------------
/webclient/editor/view/defense.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 | Defense Command
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Auto Start
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Name
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Description
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/lampmud/model/player.py:
--------------------------------------------------------------------------------
1 | from lampost.di.resource import Injected, module_inject
2 | from lampost.event.zone import Attachable
3 | from lampost.gameops.target import TargetKeys
4 | from lampost.meta.auto import AutoField
5 | from lampost.db.dbo import KeyDBO, SystemDBO
6 | from lampost.db.dbofield import DBOField
7 |
8 | log = Injected('log')
9 | ev = Injected('dispatcher')
10 | module_inject(__name__)
11 |
12 |
13 | class Player(KeyDBO, SystemDBO, Attachable):
14 | dbo_key_type = "player"
15 | dbo_set_key = "players"
16 |
17 | session = AutoField()
18 |
19 | user_id = DBOField(0)
20 | created = DBOField(0)
21 | imm_level = DBOField(0)
22 | last_login = DBOField(0)
23 | last_logout = DBOField(0)
24 | age = DBOField(0)
25 | room_id = DBOField()
26 | home_room = DBOField()
27 | instance_id = DBOField(0)
28 | instance_room_id = DBOField()
29 | group = AutoField()
30 |
31 | is_player = True
32 | can_die = True
33 |
34 | @property
35 | def edit_dto(self):
36 | dto = super().edit_dto
37 | dto['logged_in'] = "Yes" if self.session else "No"
38 | return dto
39 |
40 | @property
41 | def name(self):
42 | return self.dbo_id.capitalize()
43 |
44 | @property
45 | def location(self):
46 | try:
47 | return getattr(self.env, "title")
48 | except AttributeError:
49 | return "Unknown"
50 |
51 | def _on_loaded(self):
52 | if not self.desc:
53 | self.desc = "An unimaginably powerful immortal." if self.imm_level else "A raceless, classless, sexless player."
54 |
55 | def _on_attach(self):
56 | ev.register_p(self.autosave, seconds=20)
57 | self.active_channels = set()
58 | self.target_keys = TargetKeys(self.dbo_id)
59 | self.last_tell = None
60 |
61 | def _on_detach(self):
62 | self.session = None
63 |
64 | def check_logout(self):
65 | pass
66 |
67 | def glance(self, source, **_):
68 | source.display_line("{0}, {1}".format(self.name, self.title or "An Immortal" if self.imm_level else "A Player"))
69 |
70 | def display_line(self, text, display='default'):
71 | if text and self.session:
72 | self.session.display_line({'text': text, 'display': display})
73 |
74 | def output(self, output):
75 | if self.session:
76 | self.session.append(output)
77 |
78 | def receive_broadcast(self, broadcast):
79 | self.display_line(broadcast.translate(self), broadcast.display)
80 |
81 | def die(self):
82 | pass
83 |
84 |
85 |
--------------------------------------------------------------------------------
/webclient/editor/panels/room_reset.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{addLabel}} Reset x
4 |
5 |
6 |
7 |
8 |
9 | No valid {{addLabel}}s are available.
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{addLabel}} Id
18 |
20 |
21 |
22 |
23 |
24 |
25 | Source Area
26 |
28 |
29 |
30 |
31 |
32 |
33 |
{{resetObj.title}}
34 |
{{resetObj.desc}}
35 |
36 |
37 |
47 |
48 |
49 |
50 |
51 |
52 | Delete
53 | {{addLabel}}
54 |
55 | Add {{addLabel}}
56 |
57 | {{newAdd ? 'Cancel' : 'Close'}}
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/webclient/mud/js/storage.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_mud').service('lpStorage', ['$window', 'lpEvent', function ($window, lpEvent) {
2 |
3 | var playerId;
4 | var sessionId;
5 | var sessions;
6 | var sessionKey = 'playerSessions';
7 | var lastKey = 'lastPlayer';
8 | var immKey = 'activeImm';
9 | var immSession;
10 |
11 | function readSessions() {
12 | var value = localStorage.getItem(sessionKey);
13 | sessions = value ? JSON.parse(value) : {};
14 | }
15 |
16 | function writeSessions() {
17 | localStorage.setItem(sessionKey, JSON.stringify(sessions));
18 | if (playerId) {
19 | sessionStorage.setItem(lastKey, JSON.stringify({playerId: playerId, sessionId: sessionId,
20 | timestamp: new Date().getTime()}));
21 | } else {
22 | sessionStorage.removeItem(lastKey);
23 | }
24 | }
25 |
26 | function onLogout() {
27 | readSessions();
28 | if (sessions.hasOwnProperty(playerId)) {
29 | delete sessions[playerId];
30 | }
31 | playerId = null;
32 | writeSessions();
33 | if (immSession) {
34 | localStorage.removeItem(immKey);
35 | immSession = null;
36 | }
37 | }
38 |
39 | function updateTimestamp() {
40 | readSessions();
41 | if (playerId) {
42 | sessions[playerId] = {playerId: playerId, sessionId: sessionId, timestamp: new Date().getTime()};
43 | }
44 | writeSessions();
45 | }
46 |
47 | this.lastSession = function () {
48 | readSessions();
49 | var staleTimestamp = new Date().getTime() - 60 * 1000;
50 | var lastSession;
51 | for (playerId in sessions) {
52 | if (sessions.hasOwnProperty(playerId)) {
53 | var session = sessions[playerId];
54 | if (session.timestamp < staleTimestamp) {
55 | delete sessions[playerId];
56 | } else if (!lastSession || session.timestamp > lastSession.timestamp) {
57 | lastSession = session;
58 | }
59 | }
60 | }
61 | var lastValue = sessionStorage.getItem(lastKey);
62 | if (lastValue) {
63 | lastSession = JSON.parse(lastValue);
64 | }
65 | writeSessions();
66 | return lastSession;
67 | };
68 |
69 | lpEvent.register('connect', function (data) {
70 | sessionId = data;
71 | });
72 |
73 | lpEvent.register("heartbeat", updateTimestamp);
74 |
75 | lpEvent.register("login", function (data) {
76 | playerId = data.name.toLowerCase();
77 | if (data.imm_level) {
78 | immSession = {user_id: data.user_id, app_session_id: sessionId};
79 | localStorage.setItem(immKey, JSON.stringify(immSession));
80 | }
81 | updateTimestamp();
82 | });
83 |
84 | lpEvent.register("logout", onLogout);
85 |
86 | lpEvent.register("window_closing", function () {
87 | if (playerId) {
88 | updateTimestamp();
89 | }
90 | });
91 |
92 | }]);
93 |
--------------------------------------------------------------------------------
/lampmud/lpmud/mobile.py:
--------------------------------------------------------------------------------
1 | from lampost.di.app import on_app_start
2 | from lampost.di.config import on_config_change, config_value
3 | from lampost.di.resource import Injected, module_inject
4 | from lampost.meta.auto import TemplateField
5 | from lampost.db.dbofield import DBOField, DBOTField
6 |
7 | from lampmud.lpmud.attributes import fill_pools
8 | from lampmud.lpmud.entity import EntityLP, Skilled
9 | from lampmud.lpmud.skill import add_skill
10 | from lampmud.model.mobile import MobileTemplate, Mobile
11 |
12 |
13 | log = Injected('log')
14 | db = Injected('datastore')
15 | module_inject(__name__)
16 |
17 |
18 | @on_app_start
19 | @on_config_change
20 | def _config():
21 | global affinities
22 | global attributes
23 | global base_attr_value
24 | affinities = config_value('affinities')
25 | attributes = config_value('attributes')
26 | base_attr_value = config_value('base_attr_value')
27 |
28 |
29 | class MobileTemplateLP(MobileTemplate):
30 | class_id = 'mobile'
31 |
32 | def _on_loaded(self):
33 | if self.archetype:
34 | arch = db.load_object(self.archetype, 'archetype')
35 | for attr_name, start_value in arch.base_attrs.items():
36 | setattr(self.instance_cls, attr_name, start_value)
37 | self.desc = arch.desc
38 | else:
39 | for attr in attributes:
40 | setattr(self.instance_cls, attr['dbo_id'], base_attr_value * self.level)
41 | self.enemies = affinities[self.affinity]['enemies']
42 |
43 |
44 | class MobileLP(EntityLP, Mobile, Skilled):
45 | template_id = "mobile"
46 |
47 | default_skills = DBOTField([], 'default_skill')
48 | archetype = DBOTField()
49 | level = DBOTField(1)
50 | affinity = DBOTField('neutral')
51 | enemies = TemplateField('enemies')
52 | guard_msg = DBOField("{source} stops you from moving {exit}.")
53 |
54 | def _on_attach(self):
55 | self.skills = {}
56 | for default_skill in self.default_skills:
57 | add_skill(default_skill.skill_template, self, default_skill.skill_level, 'mobile')
58 | fill_pools(self)
59 |
60 | def _on_detach(self):
61 | self.original_env.mobiles[self.template].remove(self)
62 |
63 | def entity_enter_env(self, entity, *_):
64 | self._react_entity(entity)
65 |
66 | def entity_leave_env(self, entity, exit_action):
67 | super().entity_leave_env(entity, exit_action)
68 | self.fight.check_follow(entity, exit_action)
69 |
70 | def enter_env(self, new_env, ex=None):
71 | super().enter_env(new_env, ex)
72 | for entity in new_env.denizens:
73 | self._react_entity(entity)
74 |
75 | def _react_entity(self, entity):
76 | if entity in self.fight.opponents.keys():
77 | self.fight.add(entity)
78 | self.check_fight()
79 | elif hasattr(entity, 'affinity') and entity.affinity in self.enemies:
80 | self.start_combat(entity)
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/lampmud/editor/start.py:
--------------------------------------------------------------------------------
1 | import inspect
2 | import itertools
3 | from importlib import import_module
4 |
5 | from lampost.di.config import config_value
6 | from lampost.editor.editor import ChildrenEditor, Editor
7 | from lampost.editor.players import PlayerEditor, UserEditor
8 | from lampost.gameops.parser import action_keywords
9 | from lampost.gameops.script import Scriptable, Shadow, builders
10 | from lampost.db.registry import get_dbo_class, dbo_types, implementors, instance_implementors
11 | from lampost.server.link import link_route
12 |
13 |
14 | from lampmud.editor.areas import AreaEditor, RoomEditor
15 | from lampmud.editor.scripts import ScriptEditor
16 | from lampmud.editor.shared import SocialsEditor, SkillEditor
17 | from lampmud.env.movement import Direction
18 | from lampmud.comm.broadcast import broadcast_types, broadcast_tokens
19 | from lampmud.lpmud.skill import SkillTemplate
20 |
21 | import_module('lampost.editor.admin')
22 | import_module('lampost.editor.session')
23 | import_module('lampost.editor.dbops')
24 |
25 | AreaEditor()
26 | RoomEditor()
27 | ChildrenEditor('mobile')
28 | ChildrenEditor('article')
29 | PlayerEditor()
30 | UserEditor()
31 | SocialsEditor()
32 | Editor('race', create_level='founder')
33 | SkillEditor('attack')
34 | SkillEditor('defense')
35 | ScriptEditor()
36 |
37 |
38 | @link_route('editor/constants', 'creator')
39 | def editor_constants(**_):
40 | constants = {key: config_value(key) for key in ['attributes', 'resource_pools', 'equip_types', 'equip_slots', 'weapon_types',
41 | 'damage_types', 'damage_delivery', 'damage_groups', 'affinities', 'imm_levels']}
42 | constants['weapon_options'] = constants['weapon_types'] + [{'dbo_id': 'unused'}, {'dbo_id': 'unarmed'}, {'dbo_id': 'any'}]
43 | constants['skill_calculation'] = constants['attributes'] + [{'dbo_id': 'roll', 'name': 'Dice Roll'}, {'dbo_id': 'skill', 'name': 'Skill Level'}]
44 | constants['defense_damage_types'] = constants['damage_types'] + constants['damage_groups']
45 | constants['directions'] = Direction.ordered
46 | constants['article_load_types'] = ['equip', 'default']
47 | constants['broadcast_types'] = broadcast_types
48 | constants['broadcast_tokens'] = broadcast_tokens
49 | constants['skill_types'] = [skill_template.dbo_key_type for skill_template in dbo_types(SkillTemplate)]
50 | constants['features'] = [get_dbo_class(feature_id)().edit_dto for feature_id in ['touchstone', 'entrance', 'store']]
51 | constants['action_args'] = action_keywords
52 | shadow_types = {}
53 | for class_id, cls in itertools.chain(implementors(Scriptable), instance_implementors(Scriptable)):
54 | shadows = [{'name': name, 'args': inspect.getargspec(member.func).args} for name, member in inspect.getmembers(cls) if isinstance(member, Shadow)]
55 | if shadows:
56 | shadow_types[class_id] = shadows
57 | constants['shadow_types'] = shadow_types
58 | constants['script_builders'] = sorted((builder.dto for builder in builders), key=lambda dto: dto['name'])
59 | return(constants)
60 |
--------------------------------------------------------------------------------
/webclient/mud/view/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Welcome to {{siteTitle}}
8 |
9 |
10 |
New Here?
11 |
12 |
Create An Account
13 |
14 |
15 |
43 |
44 |
54 |
55 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/webclient/editor/panels/new_exit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dig New Exit x
4 |
5 |
6 |
7 |
30 |
31 |
32 |
33 |
34 |
35 | Area
36 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | New Room Id
46 |
48 |
50 |
51 |
52 |
53 |
54 | New Room Title
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | ×
63 | {{lastError}}
64 |
65 |
66 |
67 | Dig Exit
68 | Cancel
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/webclient/editor/view/social.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
Adjust Preview Values
44 |
45 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | {{broadcast_type.label}}
70 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/lampmud/setup/engine.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from importlib import import_module
4 |
5 | from tornado.ioloop import IOLoop
6 | from tornado.web import RedirectHandler, StaticFileHandler
7 |
8 | from lampost.util.logging import get_logger
9 | from lampost.di import resource, config, app
10 | from lampost.db.redisstore import RedisStore
11 | from lampost.db import dbconfig
12 | from lampost.util import json
13 | from lampost.db import permissions
14 | from lampost.event.system import dispatcher
15 | from lampost.gameops import friend
16 | from lampost.server import web
17 | from lampost.server.link import LinkHandler
18 | from lampost.server import pages
19 | from lampost.server import email as email_sender
20 | from lampost.server import display
21 | from lampost.server.services import AnyLoginService, PlayerListService, EditUpdateService
22 | from lampost.server import session as session_manager
23 | from lampost.server import user
24 | from lampost.server.channel import ChannelService
25 | from lampost.server import message
26 |
27 | from lampmud.env import instancemgr
28 |
29 |
30 | def start(args):
31 | json.select_json()
32 |
33 | datastore = resource.register('datastore', RedisStore(args.db_host, args.db_port, args.db_num, args.db_pw))
34 | db_config = datastore.load_object(args.config_id, dbconfig.Config)
35 | config_values = config.activate(db_config.section_values)
36 |
37 | resource.register('dispatcher', dispatcher)
38 | resource.register('perm', permissions)
39 |
40 | app_setup = import_module('{}.appstart'.format(args.app_id))
41 | app_setup.start_engine(args)
42 |
43 | resource.register('display', display)
44 | resource.register('user_manager', user)
45 | resource.register('session_manager', session_manager)
46 | resource.register('instance_manager', instancemgr)
47 | resource.register('email_sender', email_sender)
48 | resource.register('channel_service', ChannelService())
49 | resource.register('friend_service', friend)
50 | resource.register('message_service', message)
51 | resource.register('player_list_service', PlayerListService())
52 | resource.register('login_notify_service', AnyLoginService())
53 | resource.register('edit_update_service', EditUpdateService())
54 |
55 | app.start_app()
56 |
57 | pages.add_page(pages.LspPage('config.js', "var lampost_config = {{title:'{0}', description:'{1}'}};"
58 | .format(config_values['lampost_title'], config_values['lampost_description'])))
59 |
60 | tornado_logger = get_logger('tornado.general')
61 | tornado_logger.setLevel(config_values.get('tornado.log','WARN'))
62 | tornado_logger = get_logger('tornado.access')
63 | tornado_logger.setLevel(config_values.get('tornado.log', 'WARN'))
64 | web.service_root = args.service_root
65 | if args.web_files:
66 | web.add_raw_route("/", RedirectHandler, url="/webclient/lampost.html")
67 | web.add_raw_route("/webclient/(.*)", StaticFileHandler, path=os.path.abspath(args.web_files))
68 | web.add_raw_route("/lsp/(.*)", pages.LspHandler)
69 | web.add_raw_route("/link", LinkHandler)
70 | web.start_service(args.port, args.server_interface)
71 |
72 | IOLoop.instance().start()
73 |
--------------------------------------------------------------------------------
/webclient/mud/js/comm.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_mud').service('lmComm', ['lpEvent', 'lpData', 'lpRemote', 'lpDialog', function (lpEvent, lpData, lpRemote, lpDialog) {
2 |
3 | var self = this;
4 | var allLogins = false;
5 | lpEvent.register('friend_login', friendLogin);
6 | lpEvent.register('any_login', anyLogin);
7 | lpEvent.register('login', checkAllLogins);
8 | lpEvent.register('logout', function() {
9 | checkAllLogins();
10 | });
11 | lpEvent.register('notifies_updated', checkAllLogins);
12 |
13 | function checkAllLogins() {
14 | if (lpData.notifies.indexOf('allDesktop') > -1 || lpData.notifies.indexOf('allSound') > -1) {
15 | if (!allLogins) {
16 | lpRemote.registerService('login_notify_service');
17 | allLogins = true;
18 | }
19 | } else {
20 | if (allLogins) {
21 | allLogins = false;
22 | lpRemote.unregisterService('login_notify_service');
23 |
24 | }
25 | }
26 | }
27 |
28 | function friendLogin(friend_info) {
29 | if (lpData.notifies.indexOf('friendDesktop') > -1 && lpData.notifies.indexOf('allDesktop') == -1) {
30 | self.notify({icon: 'image/friendNotify.png', title: "Your friend " + friend_info.name + " logged into " + lampost_config.title, content: ''});
31 |
32 | }
33 | if (lpData.notifies.indexOf('friendSound') > -1 && lpData.notifies.indexOf('allSound') == -1) {
34 | jQuery('#sound_beep_ping')[0].play();
35 |
36 | }
37 | lpEvent.dispatch('display_line', 'Your friend ' + friend_info.name + ' just logged in', 'system');
38 | }
39 |
40 | function anyLogin(login) {
41 | if (lpData.notifies.indexOf('allDesktop') > -1) {
42 | self.notify({icon: 'image/friendNotify.png', title: "Player " + login.name + " logged into " + lampost_config.title, content: ''});
43 | }
44 |
45 | if (lpData.notifies.indexOf('allSound') > -1) {
46 | jQuery('#sound_beep_ping')[0].play();
47 | lpEvent.dispatch('display_line', login.name + ' just logged in', 'system');
48 | }
49 |
50 | }
51 |
52 | function showNotification(notify_data) {
53 | var notification = window.webkitNotifications.createNotification(notify_data.icon, notify_data.title, notify_data.content);
54 | notification.show();
55 | }
56 |
57 | this.requestNotificationPermission = function (notify_data) {
58 | lpDialog.showConfirm("Allow Notifications", "You must grant permission to allow notifications from " + lampost_config.title).then(function () {
59 | window.webkitNotifications.requestPermission(function () {
60 | self.notify(notify_data);
61 | })
62 | });
63 | };
64 |
65 | this.notify = function (notify_data) {
66 | if (!window.webkitNotifications) {
67 | return;
68 | }
69 | var permLevel = window.webkitNotifications.checkPermission();
70 | if (permLevel == 0) {
71 | showNotification(notify_data);
72 | } else if (permLevel == 1) {
73 | self.requestNotificationPermission(notify_data);
74 | }
75 | }
76 |
77 | }]);
78 |
--------------------------------------------------------------------------------
/webclient/editor/view/race.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 | Race Name
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Description
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Start Area
43 |
45 |
46 |
47 |
48 |
49 | Start Room
50 |
52 | Select Room
53 |
54 |
55 |
56 |
57 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Start Instanced
70 |
71 |
72 |
73 |
74 |
75 |
78 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/webclient/mud/dialogs/new_account.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webclient/lampost.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Lampost Mud
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
36 |
37 |
42 |
43 | {{welcome}}
44 | Logout
45 |
47 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/webclient/mud/dialogs/new_character.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webclient/editor/view/config.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Update
6 | Revert
7 |
8 |
9 |
10 |
11 |
12 |
13 | Mud Title
14 |
15 | Mud Description
16 |
17 |
18 |
19 |
20 | Start Area
21 |
22 |
23 | Start Room
24 |
25 |
26 | Auto Imm Level
27 |
28 |
29 |
30 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/webclient/editor/view/attack.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 | Attack Command
16 |
17 |
18 |
19 |
20 |
21 | Prep Time
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Name
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Description
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Attack Effect
53 |
55 |
56 |
57 | Delivery
58 |
60 |
61 |
62 |
63 | Damage Type
64 |
66 |
67 |
68 |
69 | Weapon Type
70 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/webclient/editor/view/player.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
22 |
23 | Imm Level
24 |
27 |
28 |
29 |
30 |
31 | Race
32 |
34 |
35 |
36 |
37 |
42 |
43 |
44 |
62 |
63 |
64 |
65 |
66 |
67 | Current Area
68 |
70 |
71 |
72 |
73 |
74 | Current Room
75 |
77 | Select Room
78 |
79 |
80 |
81 |
82 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/webclient/editor/panels/entrance.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{newAdd ? 'Create' : 'Modify'}} Entrance x
5 |
6 |
7 |
8 |
9 |
10 |
11 | Title
12 |
13 |
14 |
15 |
16 |
17 |
18 | Instanced
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Description
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | Command
36 |
37 |
38 |
39 |
40 | Direction
41 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | Destination Area
50 |
52 |
53 |
54 |
55 |
56 |
57 | Destination Room
58 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | {{destRoom.title}}
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | ×
77 | {{lastError}}
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | Delete Entrance
86 | Close
87 |
88 |
89 | Create Entrance
90 | Cancel
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/lampmud/lpmud/player.py:
--------------------------------------------------------------------------------
1 | from lampost.di.resource import Injected, module_inject
2 | from lampost.db.dbofield import DBOField, DBOLField
3 | from lampost.gameops.action import ActionError
4 | from lampost.di.config import config_value
5 |
6 | from lampmud.lpmud.attributes import base_pools, fill_pools
7 | from lampmud.lpmud.entity import EntityLP, Skilled
8 | from lampmud.lpmud.skill import add_skill
9 | from lampmud.model.item import ItemDBO
10 |
11 | from lampmud.model.player import Player
12 |
13 | ev = Injected('dispatcher')
14 | db = Injected('datastore')
15 | module_inject(__name__)
16 |
17 |
18 | class PlayerLP(Player, EntityLP, ItemDBO, Skilled):
19 | dbo_key_type = 'player'
20 |
21 | race = DBOLField(dbo_class_id='race')
22 | touchstone = DBOField()
23 | size = DBOField('medium')
24 | affinity = 'player'
25 | can_die = True
26 |
27 | _bind_pulse = None
28 |
29 | def _on_db_created(self):
30 | for attr_name, start_value in self.race.base_attrs.items():
31 | setattr(self, attr_name, start_value)
32 | setattr(self, 'perm_{}'.format(attr_name), start_value)
33 | fill_pools(self)
34 | if self.race.start_instanced:
35 | self.instance_room_id = self.race.start_room.dbo_id
36 | self.room_id = None
37 | else:
38 | self.room_id = self.race.start_room.dbo_id
39 |
40 | def _on_attach(self):
41 | self.auto_fight = False
42 | for skill in self.skills.values():
43 | self._apply_skill(skill)
44 | if self.race:
45 | for default_skill in self.race.default_skills:
46 | if default_skill.skill_template.dbo_key not in self.skills.keys():
47 | add_skill(default_skill.skill_template, self, default_skill.skill_level, 'race')
48 |
49 | base_pools(self)
50 | self.check_status()
51 |
52 | def check_logout(self):
53 | if self.last_opponent:
54 | self.display_line("You are in life threatening combat! You can't log out right now.", 'combat')
55 | if self.imm_level:
56 | self.display_line("(You might want to consider imposing 'peace.')")
57 | raise ActionError()
58 |
59 | def status_change(self):
60 | if not self.session:
61 | return
62 | status = self.display_status
63 | if self.last_opponent and self.last_opponent.env == self.env:
64 | status['opponent'] = self.last_opponent.display_status
65 | status['opponent']['name'] = self.last_opponent.name
66 | else:
67 | status['opponent'] = None
68 | self.session.update_status(status)
69 |
70 | def die(self):
71 | if self.can_die:
72 | self.broadcast(s="Alas, you succumb to your injuries.", e="{n} dies.", display="combat")
73 | self.display_line("Unless other help intercedes, you will be returned to your last touchstone in 90 seconds. "
74 | "You may hasten the end if you 'abandon' all hope of assistance.", 'system')
75 | self._death_effects()
76 | self._bind_pulse = ev.register_once(self.resurrect, seconds=90)
77 | else:
78 | self.broadcast(s="You die. Fortunately, you're immortal.", e="{n} examines {s} otherwise fatal wounds and shrugs.")
79 | self.health = 1
80 | self.check_status()
81 |
82 | def resurrect(self, auto=True):
83 | ev.unregister(self._bind_pulse)
84 | del self._bind_pulse
85 | res_room = None
86 | if self.touchstone:
87 | res_room = db.load_object(self.touchstone, 'room')
88 | if not res_room:
89 | res_room = db.load_object(config_value('default_start_room'), 'room')
90 | self.change_env(res_room)
91 | self.display_line("With a sick feeling, you return to consciousness")
92 | self.status = 'ok'
93 | self.health = 1
94 | self.check_status()
95 |
--------------------------------------------------------------------------------
/webclient/editor/js/feature_editors.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').controller('EditStoreCtrl', ['$scope', '$filter', function($scope, $filter) {
2 |
3 | var noCurrency = {dbo_id: ':--None--'};
4 | var noItems = {dbo_id: ':--No Items--'};
5 |
6 | $scope.store = $scope.activeFeature;
7 | $scope.currencyParent = $scope.store.currency ? $scope.store.currency.split(":")[0] : undefined;
8 | $scope.newPerm = noItems.dbo_id;
9 |
10 | $scope.setCurrencyList = function(objects) {
11 | $scope.currencyList = $filter('filter')(objects, {divisible: true});
12 | $scope.currencyList.unshift(noCurrency);
13 |
14 | for (var ix = 0; ix < $scope.currencyList.length; ix++) {
15 | if ($scope.store.currency == $scope.currencyList[ix].dbo_id) {
16 | $scope.newCurrency = $scope.store.currency;
17 | return;
18 | }
19 | }
20 | $scope.newCurrency = noCurrency.dbo_id;
21 | $scope.store.currency = null;
22 | };
23 |
24 |
25 | $scope.setPermList = function (objects) {
26 | $scope.permList = $filter('filter')(objects, {divisible: false});
27 | if ($scope.permList.length === 0) {
28 | $scope.permList = [noItems];
29 | }
30 | $scope.newPerm = $scope.permList[0].dbo_id;
31 | };
32 |
33 | $scope.updateCurrency = function() {
34 | if ($scope.newCurrency == noCurrency.dbo_id) {
35 | $scope.store.currency = null;
36 | } else {
37 | $scope.store.currency = $scope.newCurrency;
38 | }
39 | };
40 |
41 | $scope.addPerm = function() {
42 | $scope.store.perm_inven.push($scope.newPerm);
43 | };
44 |
45 | $scope.permExists = function() {
46 | return $scope.newPerm === noItems.dbo_id || $scope.store.perm_inven.indexOf($scope.newPerm) > -1;
47 | };
48 |
49 | $scope.removePerm = function(perm) {
50 | var ix = $scope.store.perm_inven.indexOf(perm);
51 | if (ix > -1) {
52 | $scope.store.perm_inven.splice(ix, 1);
53 | }
54 | };
55 |
56 | }]);
57 |
58 |
59 | angular.module('lampost_editor').controller('EditEntranceCtrl', ['$scope', 'lpEditFilters', 'lpEditor',
60 | function($scope, lpEditFilters, lpEditor) {
61 |
62 | $scope.ent_dirs = angular.copy(lpEditor.constants.directions);
63 | $scope.ent_dirs.unshift({key: 'unused', name: "Use Command"});
64 | $scope.parentFilter = lpEditFilters.hasChild('room');
65 |
66 | function initialize() {
67 | $scope.entrance = angular.copy($scope.activeFeature);
68 | $scope.newAdd = !!lpEditor.addObj;
69 | if (!$scope.entrance.direction) {
70 | $scope.entrance.direction = 'unused';
71 | }
72 | }
73 |
74 | $scope.listChange = function(children) {
75 | $scope.childList = children;
76 | $scope.entrance.destination = children[0].dbo_id;
77 | $scope.destRoom = children[0];
78 | };
79 |
80 | $scope.checkVerb = function() {
81 | if ($scope.entrance.verb) {
82 | $scope.entrance.direction = 'unused';
83 | }
84 | };
85 |
86 | $scope.checkDirection = function () {
87 | if ($scope.entrance.direction != 'unused') {
88 | $scope.entrance.verb = null;
89 | }
90 | };
91 |
92 | $scope.updateRoom = function() {
93 | $scope.entrance.destination = $scope.destRoom.dbo_id;
94 | };
95 |
96 | $scope.updateEntrance = function() {
97 | if (!$scope.entrance.title && !$scope.entrance.desc) {
98 | $scope.lastError = "Title and description required.";
99 | return;
100 | }
101 | if ($scope.entrance.direction == 'unused') {
102 | $scope.entrance.direction = null;
103 | }
104 | if ($scope.newAdd) {
105 | $scope.model.features.push($scope.entrance);
106 | } else {
107 | angular.copy($scope.entrance, $scope.activeFeature);
108 | }
109 | $scope.closeAdd();
110 | };
111 |
112 | $scope.$on('addInit', initialize);
113 |
114 | initialize();
115 |
116 |
117 |
118 | }]);
119 |
--------------------------------------------------------------------------------
/webclient/editor/js/skills_editor.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_editor').service('lpSkillService', [ 'lpCache', 'lpEditor',
2 | function(lpCache, lpEditor) {
3 |
4 | this.allSkills = function() {
5 | var skillLists = [];
6 | angular.forEach(lpEditor.constants.skill_types, function(skillType) {
7 | skillLists.push(lpCache.cachedList(skillType));
8 | });
9 | return [].concat.apply([], skillLists);
10 | };
11 |
12 | }]);
13 |
14 | angular.module('lampost_editor').controller('AttackEditorCtrl', ['$scope', 'lpEditor', 'lpEditorTypes',
15 | function ($scope, lpEditor, lpEditorTypes) {
16 |
17 | var damageList = new lpEditorTypes.ValueMap('damage_calc', 'Damage Calculation');
18 | damageList.desc = 'Calculation of Damage based on attributes and roll';
19 | damageList.options = lpEditor.constants.skill_calculation;
20 | damageList.size = 'sm';
21 | $scope.damageList = damageList;
22 |
23 | var accuracyList = new lpEditorTypes.ValueMap('accuracy_calc', 'Accuracy Calculation');
24 | accuracyList.desc = 'Calculation of Accuracy based on attributes and roll';
25 | accuracyList.options = lpEditor.constants.skill_calculation;
26 | accuracyList.size = 'sm';
27 | $scope.accuracyList = accuracyList;
28 |
29 | var costList = new lpEditorTypes.ValueMap('costs', 'Skill Costs');
30 | costList.options = lpEditor.constants.resource_pools;
31 | costList.size = 'sm';
32 | $scope.costList = costList;
33 |
34 | }]);
35 |
36 |
37 | angular.module('lampost_editor').controller('DefenseEditorCtrl', ['$scope', 'lpEditor', 'lpEditorTypes',
38 | function ($scope, lpEditor, lpEditorTypes) {
39 |
40 | var absorbList = new lpEditorTypes.ValueMap('absorb_calc', 'Absorb Calculation');
41 | absorbList.desc = 'Calculation of absorb amount based on attributes and roll';
42 | absorbList.options = lpEditor.constants.skill_calculation;
43 | absorbList.size = 'sm';
44 | $scope.absorbList = absorbList;
45 |
46 | var avoidList = new lpEditorTypes.ValueMap('avoid_calc', 'Avoid Calculation');
47 | avoidList.desc = 'Calculation of avoid chance based on attributes and roll';
48 | avoidList.options = lpEditor.constants.skill_calculation;
49 | avoidList.size = 'sm';
50 | $scope.avoidList = avoidList;
51 |
52 | var costList = new lpEditorTypes.ValueMap('costs', 'Skill Costs');
53 | costList.options = lpEditor.constants.resource_pools;
54 | costList.size = 'sm';
55 | $scope.costList = costList;
56 |
57 | $scope.damageTypes = new lpEditorTypes.OptionsList('damage_type', 'Damage Types');
58 | $scope.damageTypes.desc = 'List of damage types this defense is effective against';
59 | $scope.damageTypes.setOptions(lpEditor.constants.defense_damage_types);
60 |
61 | $scope.deliveryTypes = new lpEditorTypes.OptionsList('delivery', 'Delivery Methods');
62 | $scope.deliveryTypes.desc = 'List of delivery methods this defense is effective against';
63 | $scope.deliveryTypes.setOptions(lpEditor.constants.damage_delivery);
64 |
65 | $scope.onAutoStart = function () {
66 | if ($scope.model.auto_start) {
67 | $scope.model.verb = undefined;
68 | }
69 | };
70 |
71 | }]);
72 |
73 |
74 | angular.module('lampost_editor').controller('RaceEditorCtrl', ['$scope', 'lpEditor', 'lpEditorTypes', 'lpSkillService',
75 | function ($scope, lpEditor, lpEditorTypes, lpSkillService) {
76 |
77 | var attr_map = {};
78 |
79 | angular.forEach(lpEditor.constants.attributes, function(attr) {
80 | attr_map[attr.dbo_id] = attr;
81 | });
82 |
83 | var attrSet = new lpEditorTypes.ValueMap('base_attrs', 'Starting Attributes');
84 | attrSet.rowLabel = function(row) {
85 | return attr_map[row.key].name;
86 | };
87 |
88 | $scope.attrSet = attrSet;
89 |
90 | var skillSet = new lpEditorTypes.ValueObjList('default_skills', "Default Skills [Level]", 'skill_template', 'skill_level');
91 | skillSet.options = lpSkillService.allSkills();
92 | skillSet.optionKey = 'dbo_key';
93 | $scope.skillSet = skillSet;
94 |
95 | $scope.startRoomSelect = new lpEditorTypes.ChildSelect('start_room', 'room');
96 |
97 | }]);
98 |
--------------------------------------------------------------------------------
/webclient/common/js/directives.js:
--------------------------------------------------------------------------------
1 | angular.module('lampost_dir', []);
2 |
3 | angular.module('lampost_dir').directive("enterKey", function () {
4 | return {
5 | restrict:'A',
6 | link:function (scope, element, attrs) {
7 | element.bind('keypress', function (event) {
8 | if (event.keyCode == 13) {
9 | event.preventDefault();
10 | scope.$apply(scope.$eval(attrs.enterKey));
11 | return false;
12 | }
13 | return true;
14 | })
15 | }
16 | }
17 | });
18 |
19 | angular.module('lampost_dir').directive('autoComplete', function () {
20 | return {
21 | restrict:'A',
22 | require:'ngModel',
23 | link:function (scope, element, attrs, ngModel) {
24 | var opts = {};
25 | opts.source = scope.$eval(attrs.autoComplete);
26 | opts.updater = function (item) {
27 | ngModel.$setViewValue(item);
28 | };
29 | element.typeahead(opts);
30 | }
31 | }
32 | });
33 |
34 |
35 | angular.module('lampost_dir').directive('scrollBottom', ['$timeout', function ($timeout) {
36 | return {
37 | restrict:'A',
38 | link:function (scope, element, attrs) {
39 | scope.$watch(attrs.scrollBottom, function () {
40 | $timeout(function () {
41 | var scrollHeight = element[0].scrollHeight;
42 | if (scrollHeight) {
43 | element.scrollTop(scrollHeight);
44 | }
45 | });
46 | })
47 | }
48 | };
49 | }]);
50 |
51 | angular.module('lampost_dir').directive('history', function () {
52 | return {
53 | restrict:'A',
54 | link:function (scope, element) {
55 | element.bind('keydown', function (event) {
56 | var apply = null;
57 | if (event.keyCode == 38) {
58 | apply = function () {
59 | scope.historyUp()
60 | };
61 | } else if (event.keyCode == 40) {
62 | apply = function () {
63 | scope.historyDown()
64 | };
65 | }
66 | if (apply) {
67 | scope.$apply(apply);
68 | event.preventDefault();
69 | return false;
70 | }
71 | return true;
72 | });
73 | }
74 | }
75 | });
76 |
77 | angular.module('lampost_dir').directive("prefFocus", ['$rootScope', '$timeout', function ($rootScope, $timeout) {
78 | return {
79 | restrict:"A",
80 | link:function (scope, element) {
81 | scope.$on("refocus", forceFocus);
82 | var timer = $timeout(forceFocus);
83 |
84 | function forceFocus() {
85 | $timeout.cancel(timer);
86 | $(element)[0].focus();
87 | }
88 | }
89 | }
90 | }]);
91 |
92 | angular.module('lampost_dir').directive("lmStep", [function() {
93 | return {
94 | restrict: "A",
95 | link: function(scope, element, attrs) {
96 | element.attr("step", scope.$eval(attrs.lmStep));
97 | }
98 | }
99 | }]);
100 |
101 |
102 | angular.module('lampost_dir').directive("colorPicker", [function () {
103 | return {
104 | restrict: "A",
105 | scope: {color: '=ngModel'},
106 | link: function (scope, element) {
107 | element.spectrum({
108 | color: scope.color,
109 | change: function(color) {
110 | scope.$apply(function() {
111 | scope.color = color.toHexString(true);
112 | });
113 | },
114 | showInitial: true,
115 | showInput: true,
116 | preferredFormat: 'hex'
117 | });
118 | scope.$watch('color', function() {
119 | element.spectrum('set', scope.color);
120 | });
121 | }
122 | }
123 |
124 | }]);
125 |
--------------------------------------------------------------------------------
/lampmud/env/instance.py:
--------------------------------------------------------------------------------
1 | from lampost.db.dbofield import DBOField, DBOLField
2 |
3 | from lampost.di.resource import Injected, module_inject
4 | from lampost.gameops import target
5 | from lampost.gameops.action import ActionError
6 |
7 | from lampmud.comm.broadcast import BroadcastMap
8 | from lampmud.env.movement import Direction
9 | from lampmud.model.item import ItemDBO
10 |
11 | log = Injected('log')
12 | ev = Injected('dispatcher')
13 | instance_manager = Injected('instance_manager')
14 | module_inject(__name__)
15 |
16 |
17 | class AreaInstance():
18 | def __init__(self, instance_id):
19 | self.instance_id = instance_id
20 | self.entities = set()
21 | self.rooms = {}
22 | self.pulse_stamp = ev.current_pulse
23 |
24 | def add_entity(self, entity):
25 | self.entities.add(entity)
26 | entity.instance = self
27 | self.pulse_stamp = ev.current_pulse
28 |
29 | def remove_entity(self, entity):
30 | if entity in self.entities:
31 | del entity.instance
32 | self.entities.remove(entity)
33 | if not self.entities:
34 | self.clear_rooms()
35 | if entity.group:
36 | entity.group.instance = None
37 | instance_manager.delete(self.instance_id)
38 |
39 | def clear_rooms(self):
40 | for room in self.rooms.values():
41 | room.detach()
42 |
43 | def get_room(self, room):
44 | if not room:
45 | log.error("Null room passed to area instance")
46 | return
47 | try:
48 | my_room = self.rooms[room.dbo_id]
49 | except KeyError:
50 | my_room = room.clone()
51 | my_room.instance = self
52 | self.rooms[room.dbo_id] = my_room
53 | return my_room
54 |
55 |
56 | verb_exit = BroadcastMap(ea='{n} leaves {N}')
57 | dir_exit = BroadcastMap(ea='{n} leaves to the {N}')
58 | verb_entry = BroadcastMap(ea='{n} arrives {N}')
59 | dir_enter = BroadcastMap(ea='{n} arrives from the {N}')
60 |
61 |
62 | class Entrance(ItemDBO):
63 | class_id = 'entrance'
64 |
65 | destination = DBOLField(dbo_class_id="room", required=True)
66 | verb = DBOField('enter')
67 | direction = DBOField(None)
68 | instanced = DBOField(True)
69 | edit_required = DBOField(True)
70 |
71 | match_args = 'source',
72 |
73 | def _on_loaded(self):
74 | if self.direction:
75 | self._dir = Direction.ref_map[self.direction]
76 | self.verbs = self._dir.obj_id, self._dir.desc
77 | self.target_class = 'no_args'
78 | else:
79 | self._dir = None
80 | self.verbs = self.verb
81 | self.target_class = target.make_gen('action')
82 | if not self.title and self.verb:
83 | self.title = self.verb
84 |
85 | @property
86 | def from_name(self):
87 | return Direction.ref_map.get(self._dir.rev_key).desc if self.direction else self.title
88 |
89 | @property
90 | def entry_msg(self):
91 | return verb_entry if self.verb else verb_entry
92 |
93 | @property
94 | def exit_msg(self):
95 | return verb_exit if self.verb else dir_exit
96 |
97 | def glance(self, source):
98 | if self._dir:
99 | source.display_line('Exit: {0} {1}'.format(self._dir.desc, self.destination.title), 'exit')
100 | else:
101 | source.display_line(self.title, 'exit')
102 |
103 | def __call__(self, source):
104 | if self.instanced:
105 | if getattr(source, 'group', None):
106 | if source.group.instance:
107 | instance = source.group.instance
108 | if self.destination not in instance.rooms:
109 | raise ActionError("Your group has entered a different instance. You must leave your group to go this way.")
110 | else:
111 | instance = source.group.instance = instance_manager.next_instance()
112 | else:
113 | instance = instance_manager.next_instance()
114 | destination = instance.get_room(self.destination)
115 | else:
116 | destination = self.destination
117 | source.change_env(destination, self)
118 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Development Suspended
2 |
3 | This project is no longer updated. The active version of Lampost is now on Gitlab:
4 |
5 | [lampost_lib](https://gitlab.com/avezel/lampost_lib)
6 | [lampost_mud](https://gitlab.com/avezel/lampost_mud)
7 | [lampost_ui](https://gitlab.com/avezel/lampost-ui)
8 |
9 | These "current" versions do not have full support for the angular.js client. Instead they use a React.js/mobx based client.
10 | My development efforts are now focused on building a non-MUD game using the Lampost framework, so there will not be a React.js MUD
11 | client/editor in the near future. Accordingly if you need a MUD UI you are limited to using these Github versions of the code, or
12 | of course, I would welcome someone else expanding the lampost_ui project to include full MUD support.
13 |
14 | As always, please contact me at with any questions or ideas.
15 |
16 |
17 | ## Lampost
18 |
19 | Lampost is a multi-user virtual world building platform inspired by the thriving community of multi-user dungeons (MUDs) of the 1990s.
20 |
21 |
22 | ### Quickstart
23 |
24 | * Install Python 3.4+
25 | * Install redis-py 2.10.3+, Tornado 4.5+ and PyYAML 3.10+ (for configuration) using pip
26 | * Install Redis 2.4+
27 | * Start Redis with the redis-server script
28 | * Clone this Github repository
29 | * Run lampost_setup --imm_name YOUR_SUPERUSER_PLAYER_NAME
30 | * Run lampost.py
31 | * Point your browser at
32 |
33 | ### Lampost Components
34 |
35 | #### Application Server
36 |
37 | The Lampost application server manages user/player sessions, client communication (via Web Sockets), and
38 | the game engine via asynchronous, event driven atomic operations.
39 |
40 | #### Web Client
41 |
42 | The Lampost web client is an [angular.js](https://angularjs.org) single page application. It provides a clean UI to the
43 | Lampost Game Engine, as well as underlying support for Lampost sessions and client services.
44 |
45 | #### Game Editor
46 |
47 | The Lampost editor is a full featured administrative web client, also built on angular.js. The editor allows building
48 | traditional MUD environments in minutes, with real time creation of items, mobiles, rooms, areas (both shared and instanced)
49 | and user scripts.
50 |
51 |
52 | ### Feature Highlights
53 |
54 | #### Seamless Persistence
55 |
56 | Lampost game objects are persisted in back end data storage. Adding, subclassing, and combining persistent objects is all
57 | but invisible to the developer. Say goodbye to table definitions, xml configuration, lifecycle management, and all of the
58 | other annoying overhead of most persistence frameworks.
59 |
60 | Lampost by default uses Redis, but support for other key/value stores requires modifying only a single Lampost class.
61 |
62 | #### Intelligent Parsing
63 |
64 | Lampost includes a sophisticated command parser designed around actions in a virtual world. The parser is context aware,
65 | tailoring available actions and targets to the player, their abilities, their possessions, and their environment.
66 | The context aware algorithm results in extremely fast parsing performance.
67 |
68 | #### User Scripts
69 |
70 | Lampost has experimental support for user supplied scripts, allowing users to dynamically attach Python code to in-game objects
71 | to dramatically expand the ability to customize the game experience without modifying source code.
72 |
73 | #### Websocket API
74 |
75 | Lampost has a full featured JSON/Websocket API for creating, modifying, and deleting in game objects. This API supports the
76 | Lampost editor.
77 |
78 |
79 | ### Requirements
80 |
81 | The Lampost application server requires Python 3.4 or later. Lampost has been run successfully on Linux, Windows, and OS X (CPython),
82 | and smoke tested on [Pypy3 2.4.0](http://pypy.org) (Ubuntu).
83 |
84 | The Lampost web server is built on the [Tornado](http://www.tornadoweb.org) web server. Lampost has been tested on Tornado 4.0.2.
85 |
86 | Lampost uses [Redis](http://redis.io) as its primary, high performance key/value datastore. Lampost is currently compatible with
87 | Redis 2.4 and later versions. Lampost requires the awesome [redis-py](https://github.com/andymccurdy/redis-py) library for
88 | Redis connectivity.
89 |
90 | Finally Lampost requires PyYAML 3.x for initial configuration.
91 |
92 |
93 | ### License
94 |
95 | Lampost is covered by the MIT license, a copy of which is included in this source tree.
96 |
--------------------------------------------------------------------------------
/lampmud/model/article.py:
--------------------------------------------------------------------------------
1 | from lampost.gameops.script import Shadow
2 | from lampost.meta.auto import TemplateField
3 | from lampost.db.dbo import CoreDBO, ChildDBO
4 | from lampost.db.dbofield import DBOField, DBOTField
5 | from lampost.db.template import Template
6 | from lampost.gameops.action import ActionError
7 | from lampost.util.lputil import plural
8 |
9 | from lampmud.model.item import ItemInstance, target_keys
10 |
11 | VOWELS = {'a', 'e', 'i', 'o', 'u'}
12 |
13 |
14 | class ArticleTemplate(ChildDBO, Template):
15 | dbo_key_type = "article"
16 | dbo_parent_type = "area"
17 |
18 | def plural_name(self, quantity):
19 | if quantity == 1:
20 | return self.title
21 | return self.plural_title
22 |
23 | def _on_loaded(self):
24 | self.single_keys = target_keys(self)
25 |
26 | if self.divisible:
27 | self.plural_title = plural(self.title)
28 | self.plural_keys = target_keys(self)
29 | self.plural_keys.add(self.plural_title)
30 |
31 | def config_instance(self, instance, owner):
32 | instance.attach()
33 |
34 |
35 | class Article(ItemInstance):
36 | template_id = 'article'
37 |
38 | weight = DBOTField(0)
39 | value = DBOTField(0)
40 | divisible = DBOTField(False)
41 | art_type = DBOTField('treasure')
42 | level = DBOTField(1)
43 | quantity = DBOField()
44 | uses = DBOField()
45 | single_keys = TemplateField()
46 | plural_keys = TemplateField()
47 | plural_title = TemplateField()
48 |
49 | @property
50 | def name(self):
51 | if self.quantity and self.quantity > 1:
52 | prefix = str(self.quantity)
53 | title = self.plural_title
54 | elif self.title.lower().startswith(('a ', 'an ')):
55 | prefix = ""
56 | title = self.title
57 | else:
58 | prefix = "an" if self.title[0] in VOWELS else "a"
59 | title = self.title
60 | equipped = ' (equipped)' if self.current_slot else ''
61 | return "{} {}{}".format(prefix, title, equipped)
62 |
63 | @property
64 | def target_keys(self):
65 | if self.quantity and self.quantity > 1:
66 | return self.plural_keys
67 | return self.single_keys
68 |
69 | @Shadow
70 | def short_desc(self, observer=None):
71 | return self.name.capitalize()
72 |
73 | @Shadow
74 | def long_desc(self, observer=None):
75 | long_desc = super().long_desc(observer)
76 | if self.quantity:
77 | return "{} ({})".format(long_desc, self.quantity)
78 | return long_desc
79 |
80 | @Shadow
81 | def get(self, source, quantity=None):
82 | source.check_inven(self, quantity)
83 | gotten = self
84 | if quantity and quantity < self.quantity:
85 | gotten = self.template.create_instance()
86 | gotten.quantity = quantity
87 | self.quantity -= quantity
88 | else:
89 | source.env.remove_inven(self)
90 | source.broadcast(s="You pick up {N}", e="{n} picks up {N}", target=gotten)
91 | gotten.enter_env(source)
92 |
93 | @Shadow
94 | def drop(self, source, quantity=None):
95 | source.check_drop(self, quantity)
96 | drop = self.take_from(source, quantity)
97 | drop.enter_env(source.env)
98 | source.broadcast(s="You drop {N}", e="{n} drops {N}", target=drop)
99 |
100 | @Shadow
101 | def take_from(self, source, quantity):
102 | if quantity and quantity < self.quantity:
103 | self.quantity -= quantity
104 | drop = self.template.create_instance()
105 | drop.quantity = quantity
106 | else:
107 | drop = self
108 | source.remove_inven(self)
109 | return drop
110 |
111 | @Shadow
112 | def enter_env(self, new_env):
113 | if self.quantity:
114 | try:
115 | existing = [item for item in new_env.inven if item.template == self.template][0]
116 | existing.quantity += self.quantity
117 | return
118 | except IndexError:
119 | pass
120 | new_env.add_inven(self)
121 |
122 |
123 | class ArticleReset(CoreDBO):
124 | class_id = 'article_reset'
125 | article = DBOField(dbo_class_id='article', required=True)
126 | reset_count = DBOField(1)
127 | reset_max = DBOField(1)
128 | mobile_ref = DBOField(0)
129 | load_type = DBOField('equip')
130 |
--------------------------------------------------------------------------------
/lampmud/comm/broadcast.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from lampost.util.lputil import pronouns
4 |
5 | defaults = {'e': 's', 't': 'e', 'st': 's', 'et': 'e', 'sf': 's', 'ef': 'e', 'sa': 'st', 'ea': 'et'}
6 |
7 | broadcast_types = [{'id': bt[0], 'label': bt[1], 'reduce': bt[2], 'grid_x': bt[3], 'grid_y': bt[4]} for bt in [
8 | ('s', 'To self (no target)', 's', 0, 0),
9 | ('e', 'To others (no target)', 's', 0, 1),
10 | ('t', 'To target (target is other)', 'e', 0, 2),
11 | ('st', 'To self (target is other)', 's', 1, 0),
12 | ('et', 'To others (target is other)', 'e', 1, 1),
13 | ('sf', 'To self (target is self)', 's', 2, 0),
14 | ('ef', 'To others (target is self)', 'e', 2, 1),
15 | ('sa', 'To self (target is not living)', 'st', 3, 0),
16 | ('ea', 'To environment (target is not living)', 'et', 3, 1)]]
17 |
18 | broadcast_tokens = [{'id': token_id, 'token': token} for token_id, token in [
19 | ('n', 'Subject name'),
20 | ('N', 'Target name'),
21 | ('e', 'Subject pronoun'),
22 | ('E', 'Target pronoun'),
23 | ('s', 'Subject possessive pronoun'),
24 | ('S', 'Target possessive pronoun'),
25 | ('m', 'Subject objective pronoun'),
26 | ('M', 'Target objective pronoun'),
27 | ('f', 'Subject self pronoun'),
28 | ('F', 'Target self pronoun'),
29 | ('a', 'Absolute possessive subj'),
30 | ('A', 'Absolute possessive targ'),
31 | ('v', 'Action/verb')]]
32 |
33 | token_pattern = re.compile('\$([nNeEsSmMfFaA])')
34 |
35 |
36 | def substitute(message, source=None, target=None, verb=None, **ext_fmt):
37 | if source:
38 | s_name = getattr(source, 'name', source)
39 | s_sub, s_obj, s_poss, s_self, s_abs = pronouns[getattr(source, 'sex', 'none')]
40 | else:
41 | s_name = s_sub = s_obj = s_poss = s_self = s_abs = None
42 | if target:
43 | t_name = getattr(target, 'name', target)
44 | t_sub, t_obj, t_poss, t_self, t_abs = pronouns[getattr(target, 'sex', 'none')]
45 | else:
46 | t_name = t_sub = t_obj = t_poss = t_self = t_abs = None
47 |
48 | result = message.format(n=s_name, N=t_name, e=s_sub, E=t_sub, s=s_poss, S=t_poss,
49 | m=s_obj, M=t_obj, f=s_self, F=t_self, a=s_abs, A=t_abs,
50 | v=verb, **ext_fmt)
51 | return result
52 |
53 |
54 | class BroadcastMap:
55 | def __init__(self, **kwargs):
56 | for key, value in kwargs.items():
57 | value = token_pattern.sub(r'{\1}', value)
58 | setattr(self, key, value)
59 |
60 | def __getitem__(self, msg_key):
61 | while True:
62 | msg = getattr(self, msg_key, None)
63 | if msg:
64 | return msg
65 | msg_key = defaults.get(msg_key, None)
66 | if not msg_key:
67 | return "[EMPTY]"
68 |
69 |
70 | class Broadcast:
71 | def __init__(self, broadcast_map=None, source=None, target=None, display='default',
72 | silent=False, verb=None, ext_fmt=None, **kwargs):
73 | if broadcast_map:
74 | self.broadcast_map = broadcast_map
75 | else:
76 | self.broadcast_map = BroadcastMap(**kwargs)
77 | self.source = source
78 | self.target = target
79 | self.display = display
80 | self.silent = silent
81 | self.verb = verb
82 | self.ext_fmt = ext_fmt if ext_fmt else {}
83 |
84 | def translate(self, observer):
85 | if self.silent and observer == self.source:
86 | return None
87 | if hasattr(self.broadcast_map, 'raw'):
88 | return self.broadcast_map['raw']
89 | if not self.target:
90 | if not self.source or self.source == observer:
91 | return self.substitute('s')
92 | if self.target == self.source:
93 | if self.source == observer:
94 | return self.substitute('sf')
95 | return self.substitute('ef')
96 | if self.target == observer:
97 | return self.substitute('t')
98 | if not self.target:
99 | return self.substitute('e')
100 | if getattr(self.target, 'living', False):
101 | if self.source == observer:
102 | return self.substitute('st')
103 | return self.substitute('et')
104 | if self.source == observer:
105 | return self.substitute('sa')
106 | return self.substitute('ea')
107 |
108 | def substitute(self, version):
109 | return substitute(self.broadcast_map[version], self.source, self.target, self.verb, **self.ext_fmt)
110 |
--------------------------------------------------------------------------------
/lampmud/lpmud/combat/fight.py:
--------------------------------------------------------------------------------
1 | from lampost.di.resource import Injected, module_inject
2 | from lampost.gameops.action import ActionError
3 |
4 | from lampmud.lpmud.combat.core import consider_level
5 |
6 | log = Injected('log')
7 | ev = Injected('dispatcher')
8 | module_inject(__name__)
9 |
10 |
11 | chase_time = 120
12 |
13 |
14 | class FightStats():
15 | def __init__(self, con_level):
16 | self.attack_results = {}
17 | self.defend_results = {}
18 | self.con_level = con_level
19 | self.last_exit = None
20 | self.last_seen = ev.current_pulse
21 |
22 |
23 | class Fight():
24 | hunt_timer = None
25 | current_target = None
26 |
27 | def __init__(self, me):
28 | self.me = me
29 | self.opponents = {}
30 |
31 | def update_skills(self):
32 | self.attacks = [attack for attack in self.me.skills.values() if getattr(attack, 'msg_class', None) == 'attacked']
33 | self.attacks.sort(key=lambda x: x.points_per_pulse(self.me), reverse=True)
34 | self.defenses = [defense for defense in self.me.skills.values() if defense.template_id == 'defense' and not defense.auto_start]
35 | self.consider = self.me.considered()
36 |
37 | def add(self, opponent):
38 | try:
39 | self.opponents[opponent].last_seen = ev.current_pulse
40 | except KeyError:
41 | self.opponents[opponent] = FightStats(consider_level(self.consider, opponent.considered()))
42 | self.me.check_fight()
43 |
44 | def end(self, opponent, victory):
45 | try:
46 | del self.opponents[opponent]
47 | if opponent.last_opponent == self.me:
48 | opponent.last_opponent = None
49 | except KeyError:
50 | log.warn("Removing opponent not in fight")
51 |
52 | def end_all(self):
53 | for opponent in list(self.opponents.keys()):
54 | self.end(opponent, False)
55 | opponent.end_combat(self.me, True)
56 | self.clear_hunt_timer()
57 |
58 | def check_follow(self, opponent, ex):
59 | try:
60 | stats = self.opponents[opponent]
61 | stats.last_exit = ex
62 | stats.last_seen = ev.current_pulse
63 | self.select_action()
64 | except KeyError:
65 | pass
66 |
67 | def clear_hunt_timer(self):
68 | if self.hunt_timer:
69 | ev.unregister(self.hunt_timer)
70 | del self.hunt_timer
71 |
72 | def select_action(self):
73 | if not self.opponents:
74 | return
75 | self.clear_hunt_timer()
76 | local_opponents = [opponent for opponent in self.opponents.keys() if opponent.env == self.me.env]
77 | if local_opponents:
78 | local_opponents.sort(key=lambda opponent: opponent.health)
79 | self.select_attack(local_opponents[0])
80 | else:
81 | self.try_chase()
82 |
83 | def select_attack(self, opponent):
84 | next_available = 100000
85 | for attack in self.attacks:
86 | available = attack.available
87 | if available > 0:
88 | next_available = min(available, next_available)
89 | continue
90 | try:
91 | self.me.check_costs(attack.costs)
92 | attack.validate(self.me, opponent)
93 | except ActionError:
94 | continue
95 | self.me.last_opponent = opponent
96 | self.me.start_action(attack, {'target': opponent, 'source': self.me})
97 | return
98 | # Try again when another skill because available
99 | if next_available < 10000:
100 | ev.register_once(self.me.check_fight, next_available)
101 |
102 | def try_chase(self):
103 | stale_pulse = ev.future_pulse(-chase_time)
104 | removed = [opponent for opponent, stats in self.opponents.items() if stats.last_seen < stale_pulse]
105 | for opponent in removed:
106 | self.end(opponent, False)
107 | if not self.opponents:
108 | return
109 | for stats in sorted(self.opponents.values(), key=lambda x: x.last_seen, reverse=True):
110 | if stats.con_level < 1 and stats.last_exit in self.me.env.action_providers:
111 | try:
112 | self.me.start_action(stats.last_exit, {'source': self.me})
113 | break
114 | except ActionError:
115 | pass
116 | self.hunt_timer = ev.register_p(self.select_action, seconds=10)
117 |
--------------------------------------------------------------------------------
/webclient/common/js/autofill-event.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Autofill event polyfill ##version:1.0.0##
3 | * (c) 2014 Google, Inc.
4 | * License: MIT
5 | */
6 | (function(window) {
7 | var $ = window.jQuery || window.angular.element;
8 | var rootElement = window.document.documentElement,
9 | $rootElement = $(rootElement);
10 |
11 | addGlobalEventListener('change', markValue);
12 | addValueChangeByJsListener(markValue);
13 |
14 | $.prototype.checkAndTriggerAutoFillEvent = jqCheckAndTriggerAutoFillEvent;
15 |
16 | // Need to use blur and not change event
17 | // as Chrome does not fire change events in all cases an input is changed
18 | // (e.g. when starting to type and then finish the input by auto filling a username)
19 | addGlobalEventListener('blur', function(target) {
20 | // setTimeout needed for Chrome as it fills other
21 | // form fields a little later...
22 | window.setTimeout(function() {
23 | findParentForm(target).find('input').checkAndTriggerAutoFillEvent();
24 | }, 20);
25 | });
26 |
27 | function DOMContentLoadedListener() {
28 | // mark all values that are present when the DOM is ready.
29 | // We don't need to trigger a change event here,
30 | // as js libs start with those values already being set!
31 | forEach(document.getElementsByTagName('input'), markValue);
32 |
33 | // The timeout is needed for Chrome as it auto fills
34 | // login forms some time after DOMContentLoaded!
35 | window.setTimeout(function() {
36 | $rootElement.find('input').checkAndTriggerAutoFillEvent();
37 | }, 200);
38 | }
39 |
40 | // IE8 compatibility issue
41 | if(!window.document.addEventListener){
42 | window.document.attachEvent('DOMContentLoaded', DOMContentLoadedListener);
43 | }else{
44 | window.document.addEventListener('DOMContentLoaded', DOMContentLoadedListener, false);
45 | }
46 |
47 | return;
48 |
49 | // ----------
50 |
51 | function jqCheckAndTriggerAutoFillEvent() {
52 | var i, el;
53 | for (i=0; i 0) {
90 | forEach(this, function(el) {
91 | listener(el, newValue);
92 | });
93 | }
94 | return res;
95 | };
96 | }
97 |
98 | function addGlobalEventListener(eventName, listener) {
99 | // Use a capturing event listener so that
100 | // we also get the event when it's stopped!
101 | // Also, the blur event does not bubble.
102 | if(!rootElement.addEventListener){
103 | rootElement.attachEvent(eventName, onEvent);
104 | }else{
105 | rootElement.addEventListener(eventName, onEvent, true);
106 | }
107 |
108 | function onEvent(event) {
109 | var target = event.target;
110 | listener(target);
111 | }
112 | }
113 |
114 | function findParentForm(el) {
115 | while (el) {
116 | if (el.nodeName === 'FORM') {
117 | return $(el);
118 | }
119 | el = el.parentNode;
120 | }
121 | return $();
122 | }
123 |
124 | function forEach(arr, listener) {
125 | if (arr.forEach) {
126 | return arr.forEach(listener);
127 | }
128 | var i;
129 | for (i=0; i maxLines) {
36 | self.display.splice(0, self.display.length - maxLines);
37 | }
38 | }
39 |
40 | function updateDisplay(display) {
41 | var lines = display.lines;
42 | for (var i = 0; i < lines.length; i++) {
43 | displayLine(lines[i]);
44 | }
45 | unreadCount += lines.length;
46 | jQuery('title').text('[' + unreadCount + '] ' + title);
47 | lpEvent.dispatch("display_update");
48 | }
49 |
50 | function channelSubscribe(channel) {
51 | self.channels[channel.id] = channel.messages;
52 | lpEvent.dispatch("sort_channels");
53 | }
54 |
55 | function channelUnsubscribe(channel_id) {
56 | delete self.channels[channel_id];
57 | lpEvent.dispatch("sort_channels");
58 | }
59 |
60 | function updateChannel(channelMessage) {
61 | self.channels[channelMessage.id].push(channelMessage);
62 | updateDisplay({lines: [{text: channelMessage.text, display: channelMessage.id.split("_")[0] + "_channel"}]});
63 | }
64 |
65 | function setUser(data) {
66 | self.userId = data.user_id;
67 | self.playerIds = data.player_ids;
68 | self.notifies = data.notifies;
69 | if (data.password_reset) {
70 | lpEvent.dispatch('password_reset');
71 | }
72 | }
73 |
74 | function clearUnread() {
75 | unreadCount = 0;
76 | jQuery('title').text(title);
77 | }
78 |
79 | this.adjustLine = function (line, display) {
80 | display = display || line.display;
81 | var lineDisplay = self.userDisplays[display] || self.defaultDisplays[display];
82 | if (!lineDisplay) {
83 | return;
84 | }
85 | if (line.text == 'HRT') {
86 | line.style = {height: '2px', backgroundColor: lineDisplay.color, marginTop: '6px', marginBottom: '3px', marginRight: '3px'};
87 | line.text = '';
88 | } else if (line.text == "HRB") {
89 | line.style = {height: '2px', backgroundColor: lineDisplay.color, marginTop: '3px', marginBottom: '6px', marginRight: '3px'};
90 | line.text = '';
91 | } else {
92 | line.style = {color: lineDisplay.color};
93 | }
94 | };
95 |
96 | lpEvent.register('client_config', function (data) {
97 | self.defaultDisplays = data.default_displays;
98 | });
99 |
100 | lpEvent.register("login", function (data) {
101 | setUser(data);
102 | self.playerName = data.name;
103 | self.userDisplays = data.displays;
104 | self.immLevel = data.imm_level;
105 | self.playerId = self.playerName.toLocaleLowerCase();
106 | self.validTabs = ['status', 'channel', 'messages', 'playerList'];
107 | self.messages = data.messages;
108 |
109 | lpUtil.intSort(self.messages, 'msg_id');
110 | }, null, -100);
111 |
112 | lpEvent.register('player_update', function(data) {
113 | self.immLevel = data.imm_level;
114 | }, null, -100);
115 |
116 | lpEvent.register("user_login", setUser, null, -100);
117 | lpEvent.register("display", updateDisplay, null, -100);
118 | lpEvent.register("channel", updateChannel, null, -100);
119 | lpEvent.register("channel_subscribe", channelSubscribe, null, -100);
120 | lpEvent.register("channel_unsubscribe", channelUnsubscribe, null, -100);
121 | lpEvent.register("user_activity", clearUnread);
122 | lpEvent.register("status", function (status) {
123 | self.status = status;
124 | });
125 | lpEvent.register("logout", clear, null, -100);
126 |
127 | lpEvent.register("new_message", function (message) {
128 | self.messages.push(message);
129 | }, null, -100);
130 |
131 | lpEvent.register("player_list", function (playerList) {
132 | self.playerList = playerList;
133 | lpEvent.dispatch('player_list_update');
134 | });
135 |
136 | lpEvent.register("display_line", function(line, display) {
137 | updateDisplay({lines: [{text: line, display: display}]});
138 | })
139 |
140 | }]);
141 |
142 |
--------------------------------------------------------------------------------