moksha/api/menus/default.py | 7 moksha/controllers/root.py | 27 moksha/exc.py | 3 moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif |binary moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif |binary moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif |binary moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif |binary moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif |binary moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif |binary moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif |binary moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif |binary moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif |binary moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif |binary moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif |binary moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif |binary moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif |binary moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif |binary moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif |binary moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif |binary moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png |binary moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png |binary moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png |binary moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png |binary moksha/public/css/jquery-ui/ui.theme.css | 607 ++++++++++ moksha/templates/footer.mak | 2 moksha/templates/index.mak | 3 moksha/widgets/container/container.py | 19 moksha/widgets/jquery_ui_theme.py | 5 moksha/widgets/misc/ptd/LICENSE | 28 moksha/widgets/misc/ptd/__init__.py | 1 moksha/widgets/misc/ptd/game/creep_waves.js | 90 + moksha/widgets/misc/ptd/game/creeps.js | 353 +++++ moksha/widgets/misc/ptd/game/ptd.js | 460 +++++++ moksha/widgets/misc/ptd/game/terrain.js | 79 + moksha/widgets/misc/ptd/game/ui_modes.js | 346 +++++ moksha/widgets/misc/ptd/game/util.js | 264 ++++ moksha/widgets/misc/ptd/game/weapons.js | 398 ++++++ moksha/widgets/misc/ptd/ptd.py | 31 moksha/widgets/misc/ptd/static/jsfprocessing.js | 101 + moksha/widgets/misc/ptd/static/konami.js | 10 moksha/widgets/misc/ptd/static/style.css | 171 ++ moksha/widgets/misc/ptd/templates/ptd.mak | 319 +++++ setup.py | 12 64 files changed, 3300 insertions(+), 36 deletions(-)
New commits: commit aeef1fe9fe2e4acdde843a45c8e5e742906ea529 Merge: 8701e4b... 0b58dcf... Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:25:53 2009 -0500
Merge branch 'master' of git+ssh://git.fedorahosted.org/git/moksha
commit 8701e4b1ea456396f4fdadead1dde92043fcba4d Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:24:35 2009 -0500
Add a custom jQuery UI theme, and a widget for it, for future use.
diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif new file mode 100644 index 0000000..b26780a Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_leftright.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif new file mode 100644 index 0000000..69eb077 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_arrows_updown.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif new file mode 100644 index 0000000..70d0c82 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_close.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif new file mode 100644 index 0000000..26db434 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_doc.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif new file mode 100644 index 0000000..4efed68 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_closed.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif new file mode 100644 index 0000000..0032ff6 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_folder_open.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif new file mode 100644 index 0000000..6851f39 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_minus.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif new file mode 100644 index 0000000..74ac5cb Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_plus.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif b/moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif new file mode 100644 index 0000000..251dc16 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_11x11_icon_resize_se.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif new file mode 100644 index 0000000..29c6c70 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_down.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif new file mode 100644 index 0000000..9f95efa Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_left.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif new file mode 100644 index 0000000..bc02050 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_right.gif differ diff --git a/moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif new file mode 100644 index 0000000..28169eb Binary files /dev/null and b/moksha/public/css/jquery-ui/images/222222_7x7_arrow_up.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif new file mode 100644 index 0000000..136e626 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_leftright.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif new file mode 100644 index 0000000..4f00635 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_arrows_updown.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif new file mode 100644 index 0000000..390a759 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_close.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif new file mode 100644 index 0000000..e91c733 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_doc.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif new file mode 100644 index 0000000..85f0e0b Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_closed.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif new file mode 100644 index 0000000..f6414c7 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_folder_open.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif new file mode 100644 index 0000000..25b3e17 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_minus.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif b/moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif new file mode 100644 index 0000000..41d9534 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_11x11_icon_plus.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif new file mode 100644 index 0000000..92fdfe0 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_down.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif new file mode 100644 index 0000000..cf01ff3 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_left.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif new file mode 100644 index 0000000..3190e7a Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_right.gif differ diff --git a/moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif new file mode 100644 index 0000000..7ae34bf Binary files /dev/null and b/moksha/public/css/jquery-ui/images/454545_7x7_arrow_up.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif new file mode 100644 index 0000000..19f9d6b Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_leftright.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif new file mode 100644 index 0000000..c10451f Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_arrows_updown.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif new file mode 100644 index 0000000..326d015 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_close.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif new file mode 100644 index 0000000..7d1b5cb Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_doc.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif new file mode 100644 index 0000000..71bff05 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_closed.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif new file mode 100644 index 0000000..33a20b8 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_folder_open.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif new file mode 100644 index 0000000..777c328 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_minus.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif b/moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif new file mode 100644 index 0000000..43531ff Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_11x11_icon_plus.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif new file mode 100644 index 0000000..c91731d Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_down.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif new file mode 100644 index 0000000..d6c523b Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_left.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif new file mode 100644 index 0000000..d65b2ed Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_right.gif differ diff --git a/moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif new file mode 100644 index 0000000..165666a Binary files /dev/null and b/moksha/public/css/jquery-ui/images/888888_7x7_arrow_up.gif differ diff --git a/moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png b/moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png new file mode 100644 index 0000000..60ba001 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/dadada_40x100_textures_02_glass_75.png differ diff --git a/moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png b/moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png new file mode 100644 index 0000000..d1f8955 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/e6e6e6_40x100_textures_02_glass_75.png differ diff --git a/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png new file mode 100644 index 0000000..ac8b229 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_01_flat_0.png differ diff --git a/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png new file mode 100644 index 0000000..2c16183 Binary files /dev/null and b/moksha/public/css/jquery-ui/images/ffffff_40x100_textures_02_glass_65.png differ diff --git a/moksha/public/css/jquery-ui/ui.theme.css b/moksha/public/css/jquery-ui/ui.theme.css new file mode 100644 index 0000000..d32d49c --- /dev/null +++ b/moksha/public/css/jquery-ui/ui.theme.css @@ -0,0 +1,607 @@ +/* + * jQuery UI screen structure and presentation + * This CSS file was generated by ThemeRoller, a Filament Group Project for jQuery UI + * Author: Scott Jehl, scott@filamentgroup.com, http://www.filamentgroup.com + * Visit ThemeRoller.com +*/ + +/* + * Note: If your ThemeRoller settings have a font size set in ems, your components will scale according to their parent element's font size. + * As a rule of thumb, set your body's font size to 62.5% to make 1em = 10px. + * body {font-size: 62.5%;} +*/ + + + +/*UI accordion*/ +.ui-accordion { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + font-family: Verdana, Arial, sans-serif; + font-size: 1.1em; + border-bottom: 1px solid #d3d3d3; +} +.ui-accordion-group { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + border: 1px solid #d3d3d3; + border-bottom: none; +} +.ui-accordion-header { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + cursor: pointer; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; +} +.ui-accordion-header a { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + display: block; + font-size: 1em; + font-weight: normal; + text-decoration: none; + padding: .5em .5em .5em 1.7em; + color: #555555; + background: url(images/888888_7x7_arrow_right.gif) .5em 50% no-repeat; +} +.ui-accordion-header a:hover { + background: url(images/454545_7x7_arrow_right.gif) .5em 50% no-repeat; + color: #212121; +} +.ui-accordion-header:hover { + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; + color: #212121; +} +.selected .ui-accordion-header, .selected .ui-accordion-header:hover { + background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; +} +.selected .ui-accordion-header a, .selected .ui-accordion-header a:hover { + color: #222222; + background: url(images/222222_7x7_arrow_down.gif) .5em 50% no-repeat; +} +.ui-accordion-content { + background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x; + color: #222222; + font-size: 1em; +} +.ui-accordion-content p { + padding: 1em 1.7em 0.6em; +} + + + + + + +/*UI tabs*/ +.ui-tabs-nav { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + font-family: Verdana, Arial, sans-serif; + font-size: 1.1em; + float: left; + position: relative; + z-index: 1; + border-right: 1px solid #d3d3d3; + bottom: -1px; +} +.ui-tabs-nav li { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + float: left; + border: 1px solid #d3d3d3; + border-right: none; +} +.ui-tabs-nav li a { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + float: left; + font-size: 1em; + font-weight: normal; + text-decoration: none; + padding: .5em 1.7em; + color: #555555; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; +} +.ui-tabs-nav li a:hover { + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; + color: #212121; +} +.ui-tabs-nav li.ui-tabs-selected { + border-bottom-color: #ffffff; +} +.ui-tabs-nav li.ui-tabs-selected a, .ui-tabs-nav li.ui-tabs-selected a:hover { + background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; + color: #222222; +} +.ui-tabs-panel { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + font-family: Verdana, Arial, sans-serif; + clear:left; + border: 1px solid #d3d3d3; + background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x; + color: #222222; + padding: 1.5em 1.7em; + font-size: 1.1em; +} +.ui-tabs-hide { + display: none;/* for accessible hiding: position: absolute; left: -99999999px*/; +} + + + + + +/*slider*/ +.ui-slider { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + font-family: Verdana, Arial, sans-serif; + font-size: 1.1em; + background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x; + border: 1px solid #dddddd; + height: .8em; + position: relative; +} +.ui-slider-handle { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + position: absolute; + z-index: 2; + top: -3px; + width: 1.2em; + height: 1.2em; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; + border: 1px solid #d3d3d3; +} +.ui-slider-handle:hover { + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; + border: 1px solid #999999; +} +.ui-slider-handle-active, .ui-slider-handle-active:hover { + background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; + border: 1px solid #dddddd; +} +.ui-slider-range { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + height: .8em; + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; + position: absolute; + border: 1px solid #d3d3d3; + border-left: 0; + border-right: 0; + top: -1px; + z-index: 1; + opacity:.7; + filter:Alpha(Opacity=70); +} + + + + + + +/*dialog*/ +.ui-dialog { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + font-family: Verdana, Arial, sans-serif; + font-size: 1.1em; + background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x; + color: #222222; + border: 4px solid #dddddd; + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + z-index: 99999; +} +.ui-resizable .ui-resizable-handle { + display: block; +} +body .ui-resizable-disabled .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */ +body .ui-resizable-autohide .ui-resizable-handle { display: none; } /* use 'body' to make it more specific (css order) */ +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0px; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0px; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0px; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0px; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 13px; + height: 13px; + right: 0px; + bottom: 0px; + background: url(images/222222_11x11_icon_resize_se.gif) no-repeat 0 0; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: 0px; + bottom: 0px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: 0px; + top: 0px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: 0px; + top: 0px; +} +.ui-dialog-titlebar { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + padding: .5em 1.5em .5em 1em; + color: #555555; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; + border-bottom: 1px solid #d3d3d3; + font-size: 1em; + font-weight: normal; + position: relative; +} +.ui-dialog-title {} +.ui-dialog-titlebar-close { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + background: url(images/888888_11x11_icon_close.gif) 0 0 no-repeat; + position: absolute; + right: 8px; + top: .7em; + width: 11px; + height: 11px; + z-index: 100; +} +.ui-dialog-titlebar-close-hover, .ui-dialog-titlebar-close:hover { + background: url(images/454545_11x11_icon_close.gif) 0 0 no-repeat; +} +.ui-dialog-titlebar-close:active { + background: url(images/222222_11x11_icon_close.gif) 0 0 no-repeat; +} +.ui-dialog-titlebar-close span { + display: none; +} +.ui-dialog-content { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + color: #222222; + padding: 1.5em 1.7em; +} +.ui-dialog-buttonpane { + position: absolute; + bottom: 0; + width: 100%; + text-align: left; + border-top: 1px solid #dddddd; + background: #ffffff; +} +.ui-dialog-buttonpane button { + margin: .5em 0 .5em 8px; + color: #555555; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; + font-size: 1em; + border: 1px solid #d3d3d3; + cursor: pointer; + padding: .2em .6em .3em .6em; + line-height: 1.4em; +} +.ui-dialog-buttonpane button:hover { + color: #212121; + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; + border: 1px solid #999999; +} +.ui-dialog-buttonpane button:active { + color: #222222; + background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; + border: 1px solid #dddddd; +} +/* This file skins dialog */ +.ui-dialog.ui-draggable .ui-dialog-titlebar, +.ui-dialog.ui-draggable .ui-dialog-titlebar { + cursor: move; +} + + + + + + + +/*datepicker*/ +/* Main Style Sheet for jQuery UI date picker */ +.ui-datepicker-div, .ui-datepicker-inline, #ui-datepicker-div { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + font-family: Verdana, Arial, sans-serif; + background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x; + font-size: 1.1em; + border: 4px solid #dddddd; + width: 15.5em; + padding: 2.5em .5em .5em .5em; + position: relative; +} +.ui-datepicker-div, #ui-datepicker-div { + z-index: 9999; /*must have*/ + display: none; +} +.ui-datepicker-inline { + float: left; + display: block; +} +.ui-datepicker-control { + display: none; +} +.ui-datepicker-current { + display: none; +} +.ui-datepicker-next, .ui-datepicker-prev { + position: absolute; + left: .5em; + top: .5em; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; +} +.ui-datepicker-next { + left: 14.6em; +} +.ui-datepicker-next:hover, .ui-datepicker-prev:hover { + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; +} +.ui-datepicker-next a, .ui-datepicker-prev a { + text-indent: -999999px; + width: 1.3em; + height: 1.4em; + display: block; + font-size: 1em; + background: url(images/888888_7x7_arrow_left.gif) 50% 50% no-repeat; + border: 1px solid #d3d3d3; + cursor: pointer; +} +.ui-datepicker-next a { + background: url(images/888888_7x7_arrow_right.gif) 50% 50% no-repeat; +} +.ui-datepicker-prev a:hover { + background: url(images/454545_7x7_arrow_left.gif) 50% 50% no-repeat; +} +.ui-datepicker-next a:hover { + background: url(images/454545_7x7_arrow_right.gif) 50% 50% no-repeat; +} +.ui-datepicker-prev a:active { + background: url(images/222222_7x7_arrow_left.gif) 50% 50% no-repeat; +} +.ui-datepicker-next a:active { + background: url(images/222222_7x7_arrow_right.gif) 50% 50% no-repeat; +} +.ui-datepicker-header select { + border: 1px solid #d3d3d3; + color: #555555; + background: #e6e6e6; + font-size: 1em; + line-height: 1.4em; + position: absolute; + top: .5em; + margin: 0 !important; +} +.ui-datepicker-header option:focus, .ui-datepicker-header option:hover { + background: #dadada; +} +.ui-datepicker-header select.ui-datepicker-new-month { + width: 7em; + left: 2.2em; +} +.ui-datepicker-header select.ui-datepicker-new-year { + width: 5em; + left: 9.4em; +} +table.ui-datepicker { + width: 15.5em; + text-align: right; +} +table.ui-datepicker td a { + padding: .1em .3em .1em 0; + display: block; + color: #555555; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; + cursor: pointer; + border: 1px solid #ffffff; +} +table.ui-datepicker td a:hover { + border: 1px solid #999999; + color: #212121; + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; +} +table.ui-datepicker td a:active { + border: 1px solid #dddddd; + color: #222222; + background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; +} +table.ui-datepicker .ui-datepicker-title-row td { + padding: .3em 0; + text-align: center; + font-size: .9em; + color: #222222; + text-transform: uppercase; +} +table.ui-datepicker .ui-datepicker-title-row td a { + color: #222222; +} +.ui-datepicker-cover { + display: none; + display/**/: block; + position: absolute; + z-index: -1; + filter: mask(); + top: -4px; + left: -4px; + width: 193px; + height: 200px; +} + + + + + + + + + + + + + + +/* +Generic ThemeRoller Classes +>> Make your jQuery Components ThemeRoller-Compatible! +*/ + +/*component global class*/ +.ui-component { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; + font-family: Verdana, Arial, sans-serif; + font-size: 1.1em; +} +/*component content styles*/ +.ui-component-content { + border: 1px solid #dddddd; + background: #ffffff url(images/ffffff_40x100_textures_01_flat_0.png) 0 0 repeat-x; + color: #222222; +} +.ui-component-content a { + color: #222222; + text-decoration: underline; +} +/*component states*/ +.ui-default-state { + border: 1px solid #d3d3d3; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; + font-weight: normal; + color: #555555 !important; +} +.ui-default-state a { + color: #555555; +} +.ui-default-state:hover, .ui-hover-state { + border: 1px solid #999999; + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; + font-weight: normal; + color: #212121 !important; +} +.ui-hover-state a { + color: #212121; +} +.ui-default-state:active, .ui-active-state { + border: 1px solid #dddddd; + background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; + font-weight: normal; + color: #222222 !important; + outline: none; +} +.ui-active-state a { + color: #222222; + outline: none; +} +/*icons*/ +.ui-arrow-right-default {background: url(images/888888_7x7_arrow_right.gif) no-repeat 50% 50%;} +.ui-arrow-right-default:hover, .ui-arrow-right-hover {background: url(images/454545_7x7_arrow_right.gif) no-repeat 50% 50%;} +.ui-arrow-right-default:active, .ui-arrow-right-active {background: url(images/222222_7x7_arrow_right.gif) no-repeat 50% 50%;} +.ui-arrow-right-content {background: url(images/222222_7x7_arrow_right.gif) no-repeat 50% 50%;} + +.ui-arrow-left-default {background: url(images/888888_7x7_arrow_left.gif) no-repeat 50% 50%;} +.ui-arrow-left-default:hover, .ui-arrow-left-hover {background: url(images/454545_7x7_arrow_left.gif) no-repeat 50% 50%;} +.ui-arrow-left-default:active, .ui-arrow-left-active {background: url(images/222222_7x7_arrow_left.gif) no-repeat 50% 50%;} +.ui-arrow-left-content {background: url(images/222222_7x7_arrow_left.gif) no-repeat 50% 50%;} + +.ui-arrow-down-default {background: url(images/888888_7x7_arrow_down.gif) no-repeat 50% 50%;} +.ui-arrow-down-default:hover, .ui-arrow-down-hover {background: url(images/454545_7x7_arrow_down.gif) no-repeat 50% 50%;} +.ui-arrow-down-default:active, .ui-arrow-down-active {background: url(images/222222_7x7_arrow_down.gif) no-repeat 50% 50%;} +.ui-arrow-down-content {background: url(images/222222_7x7_arrow_down.gif) no-repeat 50% 50%;} + +.ui-arrow-up-default {background: url(images/888888_7x7_arrow_up.gif) no-repeat 50% 50%;} +.ui-arrow-up-default:hover, .ui-arrow-up-hover {background: url(images/454545_7x7_arrow_up.gif) no-repeat 50% 50%;} +.ui-arrow-up-default:active, .ui-arrow-up-active {background: url(images/222222_7x7_arrow_up.gif) no-repeat 50% 50%;} +.ui-arrow-up-content {background: url(images/222222_7x7_arrow_up.gif) no-repeat 50% 50%;} + +.ui-close-default {background: url(images/888888_11x11_icon_close.gif) no-repeat 50% 50%;} +.ui-close-default:hover, .ui-close-hover {background: url(images/454545_11x11_icon_close.gif) no-repeat 50% 50%;} +.ui-close-default:active, .ui-close-active {background: url(images/222222_11x11_icon_close.gif) no-repeat 50% 50%;} +.ui-close-content {background: url(images/222222_11x11_icon_close.gif) no-repeat 50% 50%;} + +.ui-folder-closed-default {background: url(images/888888_11x11_icon_folder_closed.gif) no-repeat 50% 50%;} +.ui-folder-closed-default:hover, .ui-folder-closed-hover {background: url(images/454545_11x11_icon_folder_closed.gif) no-repeat 50% 50%;} +.ui-folder-closed-default:active, .ui-folder-closed-active {background: url(images/222222_11x11_icon_folder_closed.gif) no-repeat 50% 50%;} +.ui-folder-closed-content {background: url(images/888888_11x11_icon_folder_closed.gif) no-repeat 50% 50%;} + +.ui-folder-open-default {background: url(images/888888_11x11_icon_folder_open.gif) no-repeat 50% 50%;} +.ui-folder-open-default:hover, .ui-folder-open-hover {background: url(images/454545_11x11_icon_folder_open.gif) no-repeat 50% 50%;} +.ui-folder-open-default:active, .ui-folder-open-active {background: url(images/222222_11x11_icon_folder_open.gif) no-repeat 50% 50%;} +.ui-folder-open-content {background: url(images/222222_11x11_icon_folder_open.gif) no-repeat 50% 50%;} + +.ui-doc-default {background: url(images/888888_11x11_icon_doc.gif) no-repeat 50% 50%;} +.ui-doc-default:hover, .ui-doc-hover {background: url(images/454545_11x11_icon_doc.gif) no-repeat 50% 50%;} +.ui-doc-default:active, .ui-doc-active {background: url(images/222222_11x11_icon_doc.gif) no-repeat 50% 50%;} +.ui-doc-content {background: url(images/222222_11x11_icon_doc.gif) no-repeat 50% 50%;} + +.ui-arrows-leftright-default {background: url(images/888888_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;} +.ui-arrows-leftright-default:hover, .ui-arrows-leftright-hover {background: url(images/454545_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;} +.ui-arrows-leftright-default:active, .ui-arrows-leftright-active {background: url(images/222222_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;} +.ui-arrows-leftright-content {background: url(images/222222_11x11_icon_arrows_leftright.gif) no-repeat 50% 50%;} + +.ui-arrows-updown-default {background: url(images/888888_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;} +.ui-arrows-updown-default:hover, .ui-arrows-updown-hover {background: url(images/454545_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;} +.ui-arrows-updown-default:active, .ui-arrows-updown-active {background: url(images/222222_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;} +.ui-arrows-updown-content {background: url(images/222222_11x11_icon_arrows_updown.gif) no-repeat 50% 50%;} + +.ui-minus-default {background: url(images/888888_11x11_icon_minus.gif) no-repeat 50% 50%;} +.ui-minus-default:hover, .ui-minus-hover {background: url(images/454545_11x11_icon_minus.gif) no-repeat 50% 50%;} +.ui-minus-default:active, .ui-minus-active {background: url(images/222222_11x11_icon_minus.gif) no-repeat 50% 50%;} +.ui-minus-content {background: url(images/222222_11x11_icon_minus.gif) no-repeat 50% 50%;} + +.ui-plus-default {background: url(images/888888_11x11_icon_plus.gif) no-repeat 50% 50%;} +.ui-plus-default:hover, .ui-plus-hover {background: url(images/454545_11x11_icon_plus.gif) no-repeat 50% 50%;} +.ui-plus-default:active, .ui-plus-active {background: url(images/222222_11x11_icon_plus.gif) no-repeat 50% 50%;} +.ui-plus-content {background: url(images/222222_11x11_icon_plus.gif) no-repeat 50% 50%;} + +/*hidden elements*/ +.ui-hidden { + display: none;/* for accessible hiding: position: absolute; left: -99999999px*/; +} +.ui-accessible-hidden { + position: absolute; left: -99999999px; +} +/*reset styles*/ +.ui-reset { + /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; +} +/*clearfix class*/ +.ui-clearfix:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +.ui-clearfix {display: inline-block;} +/* Hides from IE-mac */ +* html .ui-clearfix {height: 1%;} +.ui-clearfix {display: block;} +/* End hide from IE-mac */ + +/* Note: for resizable styles, use the styles listed above in the dialog section */ + + diff --git a/moksha/widgets/jquery_ui_theme.py b/moksha/widgets/jquery_ui_theme.py new file mode 100644 index 0000000..8afe29a --- /dev/null +++ b/moksha/widgets/jquery_ui_theme.py @@ -0,0 +1,5 @@ +from tw.api import Widget, CSSLink + +class JQueryUITheme(Widget): + css = [CSSLink(link='/css/jquery-ui/ui.theme.css', modname=__name__)] + template = '' diff --git a/moksha/widgets/misc/__init__.py b/moksha/widgets/misc/__init__.py new file mode 100644 index 0000000..e69de29
commit 8d1427ccd3964b612a4cd4e7a856580b2d82567d Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:24:00 2009 -0500
Some setup.py changes to point to the newly create tw.jquery.ui modules
diff --git a/setup.py b/setup.py index 5892dcd..aeabf48 100644 --- a/setup.py +++ b/setup.py @@ -61,6 +61,7 @@ setup( chat = moksha.api.widgets.chat:LiveChatWidget #livegraph = moksha.examples.livegraph:LiveGraphWidget #grid = moksha.api.widgets:Grid + ptd = moksha.widgets.misc.ptd:ProcessedTowerDefense
[moksha.global] # The pipeline for our live widgets @@ -68,13 +69,16 @@ setup( orbited = moksha.api.widgets.orbited:orbited_js
jquery = tw.jquery:jquery_js - jquery_ui_core = moksha.widgets.container:ui_core_js - jquery_ui_draggable = moksha.widgets.container:ui_draggable_js - jquery_ui_resizable = moksha.widgets.container:ui_resizable_js + jquery_ui_core = tw.jquery.ui:ui_core_js + jquery_ui_draggable = tw.jquery.ui:ui_draggable_min_js + jquery_ui_resizable = tw.jquery.ui:ui_resizable_min_js + #jquery_ui_dialog = tw.jquery.ui:ui_dialog_min_js #jquery_ui_tabs = tw.jquery.ui_tabs:jquery_ui_tabs_js #jquery_json_js = fedoracommunity.widgets:jquery_json_js #jquery_template_js = fedoracommunity.widgets:jquery_template_js
+ #jquery_ui_css = moksha.widgets.jquery_ui_theme:JQueryUITheme + # Enable support for the Blueprint CSS framework blueprint_ie_css = moksha.widgets.blueprint:blueprint_ie_css blueprint_screen_css = moksha.widgets.blueprint:blueprint_screen_css @@ -83,6 +87,8 @@ setup( # Blueprint plugins blueprint_fancytype_css = moksha.widgets.blueprint:blueprint_plugin_fancytype_css
+ konami_js = moksha.widgets.misc.ptd:konami + [moksha.menu] default_menu = moksha.api.menus:MokshaDefaultMenu contextual_menu = moksha.api.menus:MokshaContextMenu
commit 560220e7dbad507bf44b0bcd863fbf98390ade81 Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:23:36 2009 -0500
Minor formatting / comment
diff --git a/moksha/templates/index.mak b/moksha/templates/index.mak index c71eac8..3aa1ecc 100644 --- a/moksha/templates/index.mak +++ b/moksha/templates/index.mak @@ -18,7 +18,6 @@ ## Left sidebar </div> <div class="span-16"> - ## Main content <div id="content"></div> </div> @@ -26,7 +25,6 @@ ## Right sidebar </div> <hr class="space"> - <hr class="space"> ${footer()} </div> </a> @@ -34,6 +32,7 @@ ## Inject our global resources ${tmpl_context.moksha_global_resources()}
+ ## Setup our right-click contextual menu ${tmpl_context.contextual_menu_widget()}
</body>
commit 67b1635a701d5aa17f356705a5dfa29a02866175 Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:23:14 2009 -0500
Give our footer an id
diff --git a/moksha/templates/footer.mak b/moksha/templates/footer.mak index 81f2f39..b7f7fdf 100644 --- a/moksha/templates/footer.mak +++ b/moksha/templates/footer.mak @@ -1,6 +1,8 @@ <%def name="footer()"> +<div id="footer"> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <center><img src="/images/moksha-logo.png"/></center> +</div> </%def>
commit 1ac0a1dd8836804532703c1474c03261f0f7073f Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:22:43 2009 -0500
Improve our RootController.widgets method, making it much more simple.
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py index 8a5a8b3..37fb643 100644 --- a/moksha/controllers/root.py +++ b/moksha/controllers/root.py @@ -18,8 +18,7 @@
import moksha
-from tg import (expose, flash, require, tmpl_context, redirect, validate, - override_template) +from tg import expose, flash, require, tmpl_context, redirect, validate from tg.controllers import WSGIAppController from repoze.what import predicates
@@ -43,17 +42,21 @@ class RootController(BaseController): tmpl_context.contextual_menu_widget = moksha.menus['contextual_menu'] return dict(title='Moksha')
- @expose('mako:moksha.templates.widgetcontainer') - def widgets(self, widget, chrome=True, **kw): - tmpl_context.widget = moksha.get_widget(widget) - if not chrome or not getattr(tmpl_context.widget, 'visible', True): - override_template(self.widgets, 'mako:moksha.templates.widget') - return dict(options={}) + @expose('mako:moksha.templates.widget') + def widgets(self, widget, chrome=None, **kw): + options = {} + w = moksha._widgets.get(widget) + if not w: + raise WidgetNotFound(widget) + if chrome and getattr(w['widget'], 'visible', True): + tmpl_context.widget = container + options['content'] = w['widget'] + options['title'] = w['name'] + options['id'] = widget + '_container' else: - override_template(self.widgets, 'mako:moksha.templates.widgetcontainer') - tmpl_context.container = container - kw['id'] = widget + '_container' - return dict(title=moksha._widgets[widget]['name'], container_options=kw) + tmpl_context.widget = w['widget'] + options.update(kw) + return dict(options=options)
@expose('moksha.templates.login') def login(self, **kw): diff --git a/moksha/exc.py b/moksha/exc.py index 1a5da11..152d9d2 100644 --- a/moksha/exc.py +++ b/moksha/exc.py @@ -22,3 +22,6 @@ class MokshaException(Exception):
class ApplicationNotFound(MokshaException): pass + +class WidgetNotFound(MokshaException): + pass
commit f92194b3e49057e3bc61385881ced4ff246da963 Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:20:40 2009 -0500
Update our default menu to append all widgets to the footer, to avoid the logo flicker
diff --git a/moksha/api/menus/default.py b/moksha/api/menus/default.py index a420036..7d68bcf 100644 --- a/moksha/api/menus/default.py +++ b/moksha/api/menus/default.py @@ -54,9 +54,10 @@ class MokshaDefaultMenu(MokshaMenu): </a> """ for id, widget in moksha._widgets.iteritems(): - menu += """ - <a href="#" onclick="$('<div/>').appendTo('#content').load('/widgets/%s'); return false;">%s</a> - """ % (id, widget['name']) + if not getattr(widget['widget'], 'hidden', False): + menu += """ + <a href="#" onclick="$('<div/>').appendTo('#footer').load('/widgets/%s?chrome=True'); return false;">%s</a> + """ % (id, widget['name']) return menu
def moksha(self, *args, **kw):
commit 7678245d3c6bed35ba2e4558bf1ac4f887170f70 Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 17:16:45 2009 -0500
Add an example processing.js towerdefense widget.
diff --git a/moksha/widgets/misc/ptd/LICENSE b/moksha/widgets/misc/ptd/LICENSE new file mode 100644 index 0000000..772302f --- /dev/null +++ b/moksha/widgets/misc/ptd/LICENSE @@ -0,0 +1,28 @@ +jQuery, jQuery.hotkeys, and processing.js have been released under the MIT License +by their copyright holders. + +The code and markup of PTD itself are likewise released under the MIT License by +their copyright holders. + +Files in the assets directory however are subject to other licenses. See +assets/LICENSE + +The MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/moksha/widgets/misc/ptd/__init__.py b/moksha/widgets/misc/ptd/__init__.py new file mode 100644 index 0000000..27f4875 --- /dev/null +++ b/moksha/widgets/misc/ptd/__init__.py @@ -0,0 +1 @@ +from ptd import * diff --git a/moksha/widgets/misc/ptd/game/creep_waves.js b/moksha/widgets/misc/ptd/game/creep_waves.js new file mode 100644 index 0000000..aea8a01 --- /dev/null +++ b/moksha/widgets/misc/ptd/game/creep_waves.js @@ -0,0 +1,90 @@ +var CreepWaveController = function() { + var cwc = new Object(); + Object.extend(cwc, InertDrawable); + cwc.delay = 25000; + cwc.last = millis()-20000; + cwc.wave = 1; + cwc.spawn_wave = function(bonus) { + WIDGETS.wave.innerHTML = this.wave; + var settings = {wave:this.wave, bonus:bonus}; + var mixins = []; + + var n = Math.random(); + if (n < 0.1) + mixins.push(WaterAdverseMixin); + else if (n < 0.2) + mixins.push(WaterLovingMixin); + else if (n < 0.3) + mixins.push(MountainAdverseMixin); + else if (n < 0.4) + mixins.push(MountainLovingMixin); + else if (n < 0.5) + mixins.push(ImmuneMixin); + else if (n < 0.6) + mixins.push(FlyingMixin); + + if (this.wave % 15 == 0) { + mixins.push(BossMixin); + settings.remaining = 1; + } + else if (this.wave % 5 == 0) mixins.push(StrongMixin); + else if (this.wave % 3 == 0) mixins.push(QuickMixin); + + create_creep_wave_with_mixins(settings, mixins); + + this.wave++; + cwc.last = SET.now; + }; + cwc.update = function() { + if (SET.now - cwc.last > cwc.delay) { + this.spawn_wave(); + } + } + assign_to_depth(cwc, SET.system_render_level); + return cwc; +}; + +var CreepWave = function(settings) { + var cw = new Object(); + Object.extend(cw, InertDrawable); + cw.remaining = 20; + cw.wave = 1; + cw.last = 0; + cw.interval = 1000; + Object.extend(cw, settings); + cw.spawn_creep = function() { Creep(this.wave); }; + cw.spawn = function() { + this.remaining--; + this.spawn_creep(); + this.last = SET.now; + if (this.remaining < 1) { + this.is_dead = function() { return true; }; + if (this.bonus) + SET.score += this.bonus; + } + } + + cw.update = function() { + if (SET.now - this.last > this.interval) { + this.spawn(); + } + } + assign_to_depth(cw, SET.system_render_level); + SET.creep_variety = "Normal Creeps"; + return cw; +}; + +var create_creep_wave_with_mixins = function(settings, mixins) { + if (!mixins) mixins = []; + var cw = CreepWave(settings); + cw.knows_creep_variety = false; + cw.spawn_creep = function() { + var c = Creep(cw.wave); + mixins.forEach(function(mixin) { mixin(c); }); + if (cw.knows_creep_variety == false) { + SET.creep_variety = c.creep_type + "s"; + cw.knows_creep_variety = true; + } + } + return cw; +} diff --git a/moksha/widgets/misc/ptd/game/creeps.js b/moksha/widgets/misc/ptd/game/creeps.js new file mode 100644 index 0000000..ecf3e86 --- /dev/null +++ b/moksha/widgets/misc/ptd/game/creeps.js @@ -0,0 +1,353 @@ + + +/* + Used in by the Creep method "display stats" to + support constantly updated hp for the specific + selected creep. Conceivably one might move into + another state immediately without transitioning + into normal state before that. Preferably some + kind of state cleanup function will be added to + the state API, but at the moment it will function + correctly anyway, because the creep div will either + be invisible, or the most recent creephpupdater + will be the last one called, meaning that the + correct hp will be displayed even if there are + multiple existing creephpupdaters in the + system rendering level. + */ +var CreepHpUpdater = function(creep) { + var chp = new Object(); + Object.extend(chp, InertDrawable); + chp.update = function() { + WIDGETS.creep_hp.innerHTML = creep.hp; + } + chp.should_die = false; + chp.is_dead = function() { + if (chp.should_die || !creep || !SET.state || SET.state.name() != "CreepSelectMode" || creep.is_dead()) { + unselect(); + if (chp.kz) + chp.kz.is_dead = function() { return true; }; + return true; + } + else return false; + } + chp.draw = function() { + if (chp.kz) chp.kz.is_dead = function() { return true; }; + chp.kz = KillZone(creep.x,creep.y,15); + } + + assign_to_depth(chp, SET.system_render_level); + return chp; +} + + +/* + ### Types of creeps + + Creeps interact with terrain in a variety of ways. + Some types of creeps will be much faster on certain + squares, and much slower on others. Some types will + be ignore towers and fly over them. + + #### Terrain baseline (how a non-modified creep reacts + to certain types of terrain): + + 1. Mountains: 3/4 speed. + 2. Water: 1/2 speed. + 3. Neutral: 1/1 speed. + 4. Power Plant: 2/1 speed. + + #### Creep mixins + + 1. FlyingMixin: ignore standard pathfinding, and go in a straight line to exit. + 2. WaterAdverseMixin: very slow walking through water. + 3. WaterLovingMixin: very quick walking in water. + 4. MoutainAdverseMixin: very slow crossing mountains. + 5. MountainLovingMixin: very quick crossing mountains. + 6. ImmuneMixin: ignores terrain effects completely. + + + ### Implementation + + Each creep has an object named terrain, the keys of which + are the varying types of terrain. The value stored for each + key is a decimal which is used as a multiplier against the + creep's base speed in that type of terrain. + + */ + +/* Creep Mixins */ + +var FlyingMixin = function(creep) { + creep.creep_type = "Flying " + creep.creep_type; + creep.terrain['water'] = 1.0; + creep.terrain['mountain'] = 1.0; + creep.ignores_towers = true; + return creep; +} + +var WaterAdverseMixin = function(creep) { + creep.terrain['water'] = 0.25; + creep.creep_type = "Water-Hating " + creep.creep_type; + return creep; +} + +var WaterLovingMixin = function(creep) { + creep.terrain['water'] = 2.0; +creep.creep_type = "Water-Loving " + creep.creep_type; + return creep; +} + +var MountainAdverseMixin = function(creep) { + creep.terrain['mountain'] = 0.25; +creep.creep_type = "Mountain-Hating " + creep.creep_type; + return creep; +} + +var MountainLovingMixin = function(creep) { + creep.terrain['mountain'] = 1.25; +creep.creep_type = "Mountain-Loving " + creep.creep_type; + return creep; +} + +var ImmuneMixin = function(creep) { + creep.terrain['mountain'] = 1.0; + creep.terrain['neutral'] = 1.0; + creep.terrain['water'] = 1.0; + creep.terrain['mountain'] = 1.0; + creep.terrain['power plant'] = 1.0; + creep.creep_type = "Immune " + creep.creep_type; + return creep; +} + +var StrongMixin = function(creep) { + creep.color = color(0,255,255); + creep.size = creep.size * 1.3; + creep.hp = Math.floor(creep.hp * 2); + creep.value = Math.floor(creep.value * 1.5); + creep.creep_type = "Strong " + creep.creep_type; + return creep; +} + +var QuickMixin = function(creep) { + creep.creep_type = "Quick " + creep.creep_type; + creep.color = color(200,150,50); + creep.speed = creep.speed * 1.5; + creep.hp = Math.floor(creep.hp * .75); + creep.size = creep.size * 0.9; + creep.value = Math.floor(creep.value * 1.25); + return creep; +} + +var BossMixin = function(creep) { + creep.creep_type = "Boss " + creep.creep_type; + creep.color = color(255,100,150); + creep.size = creep.size * 1.5; + creep.hp = Math.floor(creep.hp * 10); + creep.value = Math.floor(creep.value * 20); + return creep; +} + +var Creep = function(wave) { + var cp = SET.creeps_spawned; + var c = new Object(); + c.terrain = {"entrance":1.0,"exit":1.0,"mountain":0.75,"water":0.5,"neutral":1.0,"power plant":2.0}; + + c.x = SET.entrance.x_mid; + c.y = SET.entrance.y_mid; + c.color = SET.creep_color; + c.size = SET.creep_size; + c.hp = Math.floor(SET.creep_hp * Math.pow(1.4,wave)); + c.value = SET.creep_value + wave; + c.speed = SET.creep_speed; + c.last = millis(); + c.is_dead = function() { + if (this.hp <= 0) { + SET.gold += this.value; + SET.score += this.value; + return true; + } + return false; + } + c.terrain_modified_speed = function() { + var terrain = get_terrain_at(this.gx,this.gy); + if (terrain) { + var terrain_type = terrain.type; + var terrain_modifier = c.terrain[terrain_type]; + } + else { + var terrain_modifier = 1.0; + } + return c.speed * terrain_modifier; + } + + c.ignores_towers = false; + + c.update = function() { + var gpos = pixel_to_grid(this); + this.gx = gpos.gx; + this.gy = gpos.gy; + // if it reaches the exit, kill it, but reduce the players + // lives and reduce its value to 0 (it will be collected + // and destroyed in the is_dead phase. + if (this.gx == SET.exit.gx && this.gy == SET.exit.gy) { + this.hp = -1; + this.value = 0; + SET.lives--; + if (SET.lives < 1) game_lost(); + } + else if(!this.ignores_towers) { + var elapsed = SET.now - this.last; + var terrain_modified_speed = this.terrain_modified_speed(); + var speed = (elapsed/1000) * terrain_modified_speed; + this.last = SET.now; + + var next_block = pathfind(gpos); + if (next_block == undefined){ + game_lost(); + error("Pathfinding failed. Erroring hard so that we catch these bugs."); + log("creep",this); + return; + } + + var coords = center_of_square(next_block.gx, next_block.gy) + move_towards(this,this.x,this.y,coords.x,coords.y,speed); + } + else if (this.ignores_towers) { + var elapsed = SET.now - this.last; + var terrain_modified_speed = this.terrain_modified_speed(); + var speed = (elapsed/1000) * terrain_modified_speed; + move_towards(this, this.x,this.y,SET.exit.x_mid,SET.exit.y_mid,speed) + this.last = SET.now; + } + } + c.draw = function() { + noStroke(); + fill(this.color); + ellipse(this.x,this.y,this.size,this.size); + } + c.creep_type = "Normal Creep"; + c.display_stats = function() { + WIDGETS.creep_type.innerHTML = this.creep_type; + WIDGETS.creep_hp.innerHTML = this.hp; + WIDGETS.creep_value.innerHTML = this.value + " gold"; + WIDGETS.creep.style.display = "block"; + } + SET.creeps_spawned++; + assign_to_depth(c, SET.creep_render_level); + return c; +}; + + + + +/* pathfinding */ + +var known_best_paths = undefined; +var reset_pathfinding = function(new_value) { + if (new_value == undefined){ + var coords = [SET.exit.gx, SET.exit.gy]; + new_value = {}; + SET.grid_cache_reset_all_values_for_key("valid_tower_location"); + new_value[coords] = {}; //The actual value doesn't really matter + } + var previous = known_best_paths; + known_best_paths = new_value; + return previous; +} + +//Could a creep occupy this square? +var valid_path_location = function(gx, gy) { + //out of bounds + if (gx < 0 || gy < 0) return false; + if (gx >= SET.gwidth || gy >= SET.gheight) return false; + //a tower is present + if (get_tower_at(gx,gy) != false) + return false; + //a hypothetical tower is present (when selecting a space for a new tower) + if (SET.considering_location && SET.considering_location.gx == gx && SET.considering_location.gy == gy) + return false; + return true; +} + +var pathfind = function(start_block) { +// log("pathfinding [from, to]", [start_block, SET.exit]); + if ([start_block.gx, start_block.gy] in known_best_paths) { +// log("path found from cache", start_block); + return known_best_paths[[start_block.gx, start_block.gy]].next_block.gpos; + } + + + var successors = function(block) { + var candidates = []; + var normal_dist = 10; + [[0,1],[1,0],[-1,0],[0,-1]].forEach(function(pair) { + var gpos = {gx:block.gpos.gx + pair[0], gy: block.gpos.gy + pair[1], dist:normal_dist}; + if (valid_path_location(gpos.gx, gpos.gy)) + candidates.push(gpos); + }); + + var diag_dist = 14; //sqrt(2) * 10 + [[1,1],[-1,-1],[1,-1],[-1,1]].forEach(function(pair){ + var gpos = {gx:block.gpos.gx + pair[0], gy: block.gpos.gy + pair[1], dist:diag_dist}; + if (valid_path_location(gpos.gx, gpos.gy) && valid_path_location(block.gpos.gx, gpos.gy) && valid_path_location(gpos.gx, block.gpos.gy)) + candidates.push(gpos); + }) + return candidates; + } + + + //Heuristic assumes that we move at a 45˚ angle until we've got a + //horizontal or vertical path to the goal, then we move straight + //to the goal. This is the actual behavior when there are no obstructions. + var heuristic = function(gpos) { + var dx = Math.abs(gpos.gx - SET.exit.gx); + var dy = Math.abs(gpos.gy - SET.exit.gy); + var dist = Math.min(dx,dy) * 14; + dist += (Math.max(dx,dy) - Math.min(dx,dy)) * 10 + return dist + } + + + var closed = {}; + var pqueue = [{gpos:start_block, f:heuristic(start_block), g:0}]; + while (pqueue.length > 0) { + var block = pqueue[0]; + pqueue = pqueue.slice(1); +// log("looking at", block) + if (closed[[block.gpos.gx, block.gpos.gy]] == true){ +// log("in closed, skipping", closed) + continue; + } + if ([block.gpos.gx, block.gpos.gy] in known_best_paths){ + //logging: +// rpath = []; + + while ("ancestor" in block) { + block.ancestor.next_block = block; + known_best_paths[[block.ancestor.gpos.gx, block.ancestor.gpos.gy]] = block.ancestor +// rpath.push({gx:block.gx, gy:block.gy}); + block = block.ancestor; + } +// rpath.push({gx:block.gx, gy:block.gy}); +// rpath.reverse(); +// log("known_best_paths", known_best_paths); + var result = known_best_paths[[start_block.gx, start_block.gy]].next_block.gpos; +// log("path found!", rpath); + return result; + } + closed[[block.gpos.gx, block.gpos.gy]] = true; +// log("closed", closed); + successors(block).forEach(function(s) { + var suc = {gpos:s, g:s.dist + block.g, ancestor:block}; + suc.f = suc.g + heuristic(suc.gpos); + + pqueue = insert_sorted(pqueue, suc, function(bl) { + return bl.f + }); + }) + +// log("pqueue", pqueue); + } +// log("---------pathfinding failed!----------"); +} diff --git a/moksha/widgets/misc/ptd/game/ptd.js b/moksha/widgets/misc/ptd/game/ptd.js new file mode 100644 index 0000000..e3a7180 --- /dev/null +++ b/moksha/widgets/misc/ptd/game/ptd.js @@ -0,0 +1,460 @@ +/* +Processed Tower Defense by Will Larson lethain@gmail.com + +### Processed Tower Defense + +PTD is a simple game I decided to make to get used to +the Processing.js library, and also to consider the +feasibility of writing Processing-like code, but +using Javascript instead of Java 1.3 style syntax for +all control code. + +I began prototyping the game, the first game I had +tried developing, and I got fairly far but realized +that my lack of knowledge about games had led me to +make some organizational mistakes that were making +the code increasingly incoherent and piecemeally. +So, I decided to rewrite the code to be clearer, +with the hope that it might serve as an useful +example for others. +*/ + +/* + Object life cycle. + */ + +// assign @obj to render at @depth until it dies. +// 0 is the topmost layer, and thus something at +// layer 1 will render before something at layer 0. +// Something at layer 10 will render before something +// at layer 4, and so on. This means that something +// rendered at layer 0 will draw itself ontop of anything +// rendered before layer 0. +var assign_to_depth = function(obj,depth) { + var rendering_group = SET.rendering_groups[depth]; + if (rendering_group == undefined) SET.rendering_groups[depth] = [obj]; + else rendering_group.push(obj); +} + +// updates any groups +var update_groups = function(groups) { + var obj_update = function(x) { + if (x != undefined) x.update(); + }; + var obj_is_alive = function(x) { + if ( x == undefined || x.is_dead()) return false; + return true; + }; + var obj_draw = function(x) { x.draw(); }; + for (var i=groups.length-1;i>=0;i--) { + var group = groups[i]; + if (group != undefined) { + group.forEach(obj_update); + var alive = group.filter(obj_is_alive); + alive.forEach(obj_draw); + groups[i] = alive; + } + } +} + +/* + Configuration & settings. + */ + +var default_set = function() { + var set = {}; + + // constants + set.pixels_per_square = 25; + set.half_pixels_per_square = (1.0 * set.pixels_per_square) / 2; + set.height = 450; + set.width = 600; + set.framerate = 60; + set.gheight = Math.floor(set.height / set.pixels_per_square); + set.gwidth = Math.floor(set.width / set.pixels_per_square); + + /* + ### Grid Cache + + This is a place to store any data that should be associated + with a specific grid square. For example, each grid square + will have the Terrain occupying it stored there, and a grid + square's tower could be retrieved this way as well. + + ### Using the Grid Cache + + The Grid Cache is, as it is named, intended to be + used as a cache. This means it shouldn't be relied upon as the + definitive answer to a question, but should be used to store + answers to frequently answered questions. + + For example, the find_tower_at(gx,gy) method is used to find + any towers existing at (gx,gy). That method should first check + the cache for a key of 'tower', and use it if it exists, but + should be able to find the tower without the cache as well + (by scanning through all towers looking for the correct + one). + + ### Invalidating Entries in Grid Cache + + Entries in the Grid Cache will be cleared out each time the + game is reset, and beyond that invalidating of key/value pairs + must be done manually. + + For example, upon selling a tower the value of the tower stored + in the cache should be extinguished. + */ + set.grid_cache = {}; + + + set.grid_cache_at = function(gx,gy) { + var gx_cache = set.grid_cache[gx]; + if (!gx_cache) { + gx_cache = {}; + set.grid_cache[gx] = gx_cache; + } + var gy_cache = gx_cache[gy]; + if (!gy_cache) { + gy_cache = {}; + gx_cache[gy] = gy_cache; + } + return gy_cache; + } + + set.grid_cache_reset_all_values_for_key = function(key) { + for(gx in set.grid_cache) { + for (gy in set.grid_cache[gx]) { + delete set.grid_cache[gx][gy][key]; + } + } + } + + // colors + set.bg_colors = {neutral:color(90,80,70), + positive:color(60,80,250), + negative:color(250,80,60)}; + set.bg_color = set.bg_colors.neutral; + set.grid_color = color(255,255,255); + set.entrance_color = color(100,255,100); + set.exit_color = color(255,100,50); + set.killzone_color = color(200,50,50,0.5); + set.creep_color = color(255,255,0); + + // rendering groups + set.rendering_groups = []; + for (var i=0; i <= 7; i++) set.rendering_groups.push([]); + set.system_render_level = 7; + set.square_render_level = 6; + set.killzone_render_level = 5; + set.grid_render_level = 4; + set.tower_render_level = 3; + set.build_zone_render_level = 2; + set.creep_render_level = 1; + set.bullet_render_level = 0; + + // game state + set.state = undefined; + + // game values + set.creep_variety = "Normal Creeps"; + set.creep_size = 10; + set.creep_hp = 10; + set.creep_value = 1; + set.creep_speed = 50; + set.missile_blast_radius = 5; + set.missile_damage = 100; + set.gold = 200; + set.creeps_spawned = 0; + set.max_creeps = 1; + set.score = 0; + set.lives = 20; + set.nukes = 3; + set.bomb_cost = 50; + + return set +}; +var SET; + +var fetch_ui_widgets = function() { + var w = {}; + // status bar widgets + w.score = document.getElementById("score"); + w.gold = document.getElementById("gold"); + w.lives = document.getElementById("lives"); + w.nukes_left = document.getElementById("nukes_left"); + w.creep_variety = document.getElementById("creep_variety"); + w.wave = document.getElementById("wave"); + w.till_next_wave = document.getElementById("till_next_wave"); + w.bomb_cost = document.getElementById("bomb_cost"); + + // tower widgets + w.tower = document.getElementById("tower"); + w.tower_type = document.getElementById("tower_type"); + w.tower_range = document.getElementById("tower_range"); + w.tower_damage = document.getElementById("tower_damage"); + w.tower_rate = document.getElementById("tower_rate"); + w.tower_upgrade_button = document.getElementById("tower_upgrade_button"); + w.tower_sell_button = document.getElementById("tower_sell_button"); + + // creep widgets + w.creep = document.getElementById("creep"); + w.creep_type = document.getElementById("creep_type"); + w.creep_hp = document.getElementById("creep_hp"); + w.creep_value = document.getElementById("creep_value"); + + return w; +}; +var WIDGETS; + +/* + Drawable objects (grid, towers, creeps, everything). + */ + +// prototype for grid lines and colored squares +var InertDrawable = new Object(); +Object.extend(InertDrawable, { + update:function() {}, + is_dead:function() { return false; }, + draw:function() {} + }); + + +// responsible for updating settings in SET +// at the very beginning of a rendering cycle +var SettingUpdater = function() { + var su = new Object(); + Object.extend(su, InertDrawable); + su.update = function() { SET.now = millis(); } + assign_to_depth(su, SET.system_render_level); + return su; +}; + +var UIUpdater = function() { + var uiu = new Object(); + Object.extend(uiu, InertDrawable); + + uiu.update = function() { + WIDGETS.creep_variety.innerHTML = SET.creep_variety; + WIDGETS.score.innerHTML = SET.score; + WIDGETS.gold.innerHTML = SET.gold; + WIDGETS.lives.innerHTML = SET.lives; + WIDGETS.nukes_left.innerHTML = SET.nukes + " left"; + WIDGETS.till_next_wave.innerHTML = Math.floor(((SET.creep_wave_controller.last + SET.creep_wave_controller.delay) - SET.now) / 1000) + }; + assign_to_depth(uiu, SET.system_render_level); + return uiu; +} + + +var Grid = function() { + var grid = new Object(); + Object.extend(grid, InertDrawable); + grid.draw = function() { + stroke(SET.grid_color); + var p = SET.pixels_per_square; + var w = SET.width; + var h = SET.height; + for (i = 0; i<w; i+=p) { + line(i, 0, i, h); + } + for (i = 0; i<h; i+=p) { + line(0,i,w,i); + } + }; + assign_to_depth(grid, SET.grid_render_level); + return grid; +}; + + +var GridSquare = function(gx,gy,color) { + var square = new Object(); + Object.extend(square, InertDrawable); + square.gx = gx; + square.gy = gy; + square.x = grid_to_pixel(gx); + square.y = grid_to_pixel(gy); + var mid = center_of_square(gx,gy); + square.x_mid = mid.x; + square.y_mid = mid.y; + return square; +} + +var Square = function(gx,gy,color) { + var square = GridSquare(gx,gy,color); + square.color = color; + square.draw = function() { + noStroke(); + fill(this.color); + draw_square_in_grid(this.gx,this.gy); + } + assign_to_depth(square, SET.square_render_level); + return square; +}; +var ExitSquare = function(gx,gy) { + var square = Square(gx,gy,SET.exit_color); + square.type = "exit"; + square.draw = function() { + noStroke(); + fill(SET.exit_color); + draw_square_in_grid(this.gx,this.gy); + noFill(); + stroke("black"); + draw_circle_in_grid(this.gx,this.gy); + } + return square; +} + + +var spawn_wave = function() { + if (!SET.state || + (SET.state.name() != "GameOverMode" && + SET.state.name() != "PauseMode")) { + //a bonus for bravery, to be paid when the creep wave thus spawned is done + var bonus = Math.floor(((SET.creep_wave_controller.last + SET.creep_wave_controller.delay) - SET.now) / 100); + SET.creep_wave_controller.spawn_wave(bonus); + } +} + +var nuke_creeps = function() { + if (SET.nukes > 0) { + var creeps = SET.rendering_groups[SET.creep_render_level]; + creeps.forEach(function(x) { + x.hp = -1; + x.value = 0; // no gold for nuked creeps + }); + play_sound("nuke"); + SET.nukes--; + } + else {error("You're all out of nukes!")} +}; + + +var pause_resume = function() { + if (SET.state) { + var state_name = SET.state.name(); + if (state_name == "GameOverMode") + ; + else if (state_name == "PauseMode") { + unselect(); + } + else { + unselect(); + SET.state = new PauseMode(); + SET.state.set_up(); + } + } + else { + SET.state = new PauseMode(); + SET.state.set_up(); + } +}; + +var game_lost = function() { + unselect(); + attempt_to_enter_ui_mode(new GameOverMode()); +} + +/* + Game level functions. Starting, resetting, etc. + */ + +var generate_map = function() { + SET.entrance = Square(0, random(SET.gheight-1), SET.entrance_color); + SET.entrance.type = "entrance"; + SET.exit = ExitSquare(SET.gwidth-1, random(SET.gheight-1)); + populate_terrains(); +} + +var reset_game = function() { + SET = default_set(); + WIDGETS = fetch_ui_widgets(); + WIDGETS.bomb_cost.innerHTML = SET.bomb_cost; + SettingUpdater(); + UIUpdater(); + //Grid(); + generate_map(); + SET.creep_wave_controller = CreepWaveController(); + reset_pathfinding(); + $('').trigger("game_over",false); +}; + +/* + Mouse functions. + */ + +var on_mouse_moved = function() { + if (SET.state && SET.state.draw) { + var pos = mouse_pos(); + SET.state.draw(pos.x,pos.y); + } +}; + +// user-interface modes that can be entered by clicking within +// the game canvas (i.e. this does not include states reached +// by clicking an html button) +var UI_MODES_FROM_CLICK = [TowerSelectMode, CreepSelectMode]; + +var on_mouse_press = function() { + var pos = mouse_pos(); + if (SET.state) { + if (SET.state.is_legal(pos.x,pos.y)) { + SET.state.action(pos.x,pos.y); + } + if (SET.state.can_leave_mode(pos.x,pos.y)) { + unselect(); + } + } + if (!SET.state) { + var len = UI_MODES_FROM_CLICK.length; + for (var i=0;i<len;i++) { + var modeFunc = UI_MODES_FROM_CLICK[i]; + var mode = new modeFunc(); + if (mode.can_enter_mode(pos.x,pos.y)) { + SET.state = mode; + SET.state.set_up(pos.x,pos.y); + break; + } + } + } +} + + +var message = function(msg) { + $('').trigger("message", msg); +} + +var unselect = function() { + if (SET.state) SET.state.tear_down(); + SET.state = undefined; + $('').trigger("no_mode"); +} + +var error = function(msg) { + $('').trigger("error", msg); +} + +/* + Main game loop. + */ + +var start_tower_defense = function() { + setup = function() { + $('#pause_button').html("Pause"); + set_canvas("tower_defense"); + reset_game(); + size(SET.width, SET.height); + frameRate(SET.framerate); + mouseMoved(on_mouse_moved); + mousePressed(on_mouse_press); + initProcessing(); + } + draw = function() { + if (SET.state) { + var state_name = SET.state.name(); + if (state_name == "GameOverMode" || state_name == "PauseMode") return + } + background(SET.bg_color); + update_groups(SET.rendering_groups); + } + setup(); +} diff --git a/moksha/widgets/misc/ptd/game/terrain.js b/moksha/widgets/misc/ptd/game/terrain.js new file mode 100644 index 0000000..70327cf --- /dev/null +++ b/moksha/widgets/misc/ptd/game/terrain.js @@ -0,0 +1,79 @@ + +/* File to contain Terrain implementation. */ + +var NeutralTerrain = function(gx,gy) { + var terrain_color = color(200,200,200); + var t = Square(gx,gy,terrain_color); + t.type = "neutral"; + t.tower_range_modifier = 1.0; + t.tower_damage_modifier = 1.0; + t.tower_frequency_modifier = 1.0; + return t; +} + +var WaterTerrain = function(gx,gy) { + var t = NeutralTerrain(gx,gy); + t.color = color(78,150,236); + t.type = "water"; + return t; +} + +var MountainTerrain = function(gx,gy) { + var t = NeutralTerrain(gx,gy); + t.color = color(228,51,51); + t.type = "mountain"; + t.tower_range_modifier = 1.25; + return t; +} + +var PowerPlantTerrain = function(gx,gy) { + var t = NeutralTerrain(gx,gy); + t.color = color(189,194,78); + t.type = "power plant"; + t.tower_damage_modifier = 2.0; + return t; +} + +var populate_terrains = function() { + var p_mountains = SET.terrain_percent_mountains || 0.05; + var p_water = SET.terrain_percent_water || 0.1; + var p_power_plant = SET.terrain_percent_power_plant || 0.01; + // remainder is neutral terrain + + var range_mountain = p_mountains; + var range_water = p_mountains + p_water; + var range_power_plant = p_power_plant + range_water; + // remainder is neutral terrain + + var entrance = SET.entrance; + var exit = SET.exit; + var gwidth = SET.gwidth; + var gheight = SET.gheight; + + // column with entrance & exit squares + // are all neutral terrain + for (var gy=0; gy<gheight; gy++) { + if ( gy != entrance.gy ) { + NeutralTerrain(0,gy); + } + if ( gy != exit.gy ) { + NeutralTerrain(gwidth-1,gy); + } + } + + for (var gx=1; gx<gwidth-1; gx++) { + for (var gy=0; gy<gheight; gy++) { + var n = Math.random(); + if (n <= range_mountain) + MountainTerrain(gx,gy); + else if (n <= range_water) + WaterTerrain(gx,gy); + else if (n <= range_power_plant) + PowerPlantTerrain(gx,gy); + else + NeutralTerrain(gx,gy); + } + } + + +} diff --git a/moksha/widgets/misc/ptd/game/ui_modes.js b/moksha/widgets/misc/ptd/game/ui_modes.js new file mode 100644 index 0000000..f187598 --- /dev/null +++ b/moksha/widgets/misc/ptd/game/ui_modes.js @@ -0,0 +1,346 @@ +/* + User-interface functions. + */ + +var UserInterfaceMode = function() { + this.action = function(x,y) { + // called when the mouse is clicked, if is_legal + }; + this.is_legal = function(x,y) { + // returns true,false or undefined. + // if true, then the UI mode's action can be undertaken + // at @x, @y. If false, then it cannot be undertaken. + // Otherwise, the UI has no concept of legality. + // The distinction between undefined and true lies in + // visual cues presented to the user. + return undefined; + }; + this.draw = function(x,y) { + // draw any relevant graphics at the mouse's location + }; + this.set_up = function() { + // do any setup before entering the UI mode + }; + this.tear_down = function() { + // perform any clean up before exiting the UI mode. + }; + this.can_leave_mode = function(x,y) { + // used to check if the the UI mode can be left + return true; + }; + this.can_enter_mode = function(x,y) { + // used for checking if a UI can be invoked + return true; + }; + this.name = function() { + return "UserInterfaceMode"; + }; +}; + +var attempt_to_enter_ui_mode = function(mode, error_msg) { + /* + This is only necessary for button based UI modes. This + logic is already handled for UI modes invoked by mouse + clicks in the game canvas. + */ + if (!SET.state || SET.state.can_leave_mode()) { + unselect(); + if (mode.can_enter_mode()) { + SET.state = mode; + var pos = mouse_pos(); + SET.state.set_up(pos.x,pos.y); + } + else if (!error_msg) + {error("Not enough gold, you need at least " + mode.cost)}; + } +}; + +var BuildTowerMode = function() { + var is_blocking_paths = function(gpos) { + //if the proposed tower isn't along any known path, it's not in + //the way + pathfind({gx:SET.entrance.gx, gy:SET.entrance.gy}); + if (!([gpos.gx,gpos.gy] in known_best_paths)) { + var safe = true; +// log("looking at diagonals of",gpos); + [[1,1],[-1,-1],[1,-1],[-1,1]].forEach(function(pair) { +// log("diagonal",{gx:gpos.gx + pair[0], gy:gpos.gy + pair[1]}); + if (!valid_path_location(gpos.gx + pair[0], gpos.gy + pair[1])){ +// log("diagonal disqualified from free is_blocking call",gpos); + safe = false; + } + }); + if (safe) + return true; + } + +// log("pathfinding on behaf of", gpos); + + //check that we can pathfind from the entrance + //to the exit, and from each creep to the exit + SET.considering_location = gpos; + var previous_pathfinding = reset_pathfinding(); + var valid = pathfind({gx:SET.entrance.gx, gy:SET.entrance.gy}); + var creeps = SET.rendering_groups[SET.creep_render_level]; + creeps.forEach(function(creep){ + valid = valid && pathfind(pixel_to_grid(creep)); + }); + SET.considering_location = undefined; + reset_pathfinding(previous_pathfinding); + if (!valid) + return false; + return true; + } + + this.is_legal = function(x,y) { + var gpos = pixel_to_grid(x,y); + if (can_build_here(gpos.gx,gpos.gy) == false) return false; + + var cache = SET.grid_cache_at(gpos.gx, gpos.gy); + if (cache["valid_tower_location"] == undefined){ +// log("grid grid miss"); + cache["valid_tower_location"] = is_blocking_paths(gpos); +// log("placing tower ok?", cache["valid_tower_location"]); + } +// else log("in grid cache"); + + return cache["valid_tower_location"]; + }; + this.draw = function(x,y) { + var gpos = pixel_to_grid(x,y); + var mid = center_of_square(gpos); + var radius = SET.half_pixels_per_square; + if (this.br) + this.br.is_dead = function() { return true; } + this.br = BuildRadius(mid.x,mid.y,radius); + if (this.is_legal(x,y)) + this.br.color = SET.bg_colors.positive; + else + this.br.color = SET.bg_colors.negative; + + }; + this.set_up = function(x,y) { + this.draw(x,y); + $('').trigger(this.name()); + }; + this.tear_down = function() { + if (this.br) { + this.br.is_dead = function() { return true; }; + } + }; + this.action = function(x,y) { + var gpos = pixel_to_grid(x,y); + this.tower(gpos.gx,gpos.gy); + SET.gold -= this.cost; + reset_pathfinding(); + }; + this.can_enter_mode = function(x,y) { + if (SET.gold >= this.cost) return true; + else return false; + }; + this.can_leave_mode = function() { + //if we don't have enough money, we can't keep building + if (SET.gold < this.cost) return true; + //remain in build mode if shift is held down + return !shift_down; + }; + this.name = function() { + return "BuildTowerMode"; + }; +}; +BuildTowerMode.prototype = new UserInterfaceMode(); + +var BuildMissileTowerMode = function() { + this.cost = 100; + this.tower = MissileTower; + this.name = function() { + return "BuildMissileTowerMode"; + }; +}; +BuildMissileTowerMode.prototype = new BuildTowerMode(); + + +var build_missile_tower = function() { + attempt_to_enter_ui_mode(new BuildMissileTowerMode()); +}; + +var BuildCannonTowerMode = function() { + this.cost = 75; + this.tower = CannonTower; + this.name = function() { + return "BuildCannonTowerMode"; + }; +}; +BuildCannonTowerMode.prototype = new BuildTowerMode(); + + +var build_cannon_tower = function() { + attempt_to_enter_ui_mode(new BuildCannonTowerMode()); +}; + +var BuildLaserTowerMode = function() { + this.cost = 25; + this.tower = LaserTower; + this.name = function() { + return "BuildLaserTowerMode"; + }; +}; +BuildLaserTowerMode.prototype = new BuildTowerMode(); + +var build_laser_tower = function() { + attempt_to_enter_ui_mode(new BuildLaserTowerMode()); +}; + +var BuildGatlingTowerMode = function() { + this.cost = 50; + this.tower = GatlingTower; + this.name = function() { + return "BuildGatlingTowerMode"; + } +}; +BuildGatlingTowerMode.prototype = new BuildTowerMode(); + +var build_gatling_tower = function() { + attempt_to_enter_ui_mode(new BuildGatlingTowerMode()); +} + + +/* TowerSelectMode */ + +var TowerSelectMode = function() { + this.set_up = function(x,y) { + var gpos = pixel_to_grid(x,y); + this.tower = get_tower_at(gpos.gx,gpos.gy); + if (this.tower) { + this.tower.display_stats(); + this.killzone = KillZone(this.tower.x_mid, + this.tower.y_mid, + this.tower.range*SET.pixels_per_square); + WIDGETS.tower.style.display = "block"; + } + }; + this.tear_down = function() { + WIDGETS.tower.style.display = "none"; + if (this.killzone) + this.killzone.is_dead = function() { return true; }; + }; + this.can_enter_mode = function(x,y) { + var gpos = pixel_to_grid(x,y); + var tower = get_tower_at(gpos.gx,gpos.gy); + return (tower == false) ? false : true; + } + +}; +TowerSelectMode.prototype = new UserInterfaceMode(); + +var select_tower = function() { + SET.state = new TowerSelectMode(); +}; + +/* CreepSelectMode */ + +var CreepSelectMode = function() { + this.set_up = function(x,y) { + this.creep = get_creep_nearest(x,y); + if (this.creep) { + this.creep.display_stats(); + WIDGETS.creep.style.display = "block"; + this.hp_updater = CreepHpUpdater(this.creep); + } + }; + this.tear_down = function() { + WIDGETS.creep.style.display = "none"; + if (this.hp_updater) { + this.hp_updater.should_die = true; + } + }; + this.name = function() { + return "CreepSelectMode"; + }; +}; +CreepSelectMode.prototype = new UserInterfaceMode(); + +var select_creep = function() { + SET.state = CreepSelectMode(); +}; + +/* AimBombMode */ + +var AimBombMode = function() { + this.cost = SET.bomb_cost; + this.radius = SET.missile_blast_radius * SET.pixels_per_square * 1.0; + this.draw = function(x,y) { + if (this.mr) this.mr.is_dead = function() { return true; }; + this.mr = MissileRadius(x,y,this.radius); + } + this.set_up = function(x,y) { + this.draw(x,y); + $('').trigger("AimBombMode"); + } + this.tear_down = function() { + if (this.mr) this.mr.is_dead = function() { return true; }; + } + this.can_enter_mode = function(x,y) { + if (SET.gold >= this.cost) return true; + else return false; + }; + this.name = function() { + return "AimBombMode"; + }; + this.is_legal = function() { return true; }; + this.action = function(x,y) { + var creeps = SET.rendering_groups[SET.creep_render_level]; + var l = creeps.length; + var range = Math.floor(this.radius); + for (var i=0;i<l;i++) { + var creep = creeps[i]; + var d = Math.floor(dist(x,y,creep.x,creep.y)); + if (d <= range) + creep.hp = Math.floor(creep.hp / 2); + } + play_sound("bomb"); + SET.gold -= this.cost; + var cost_increase = SET.bomb_cost * 0.25; + if (cost_increase < 25) cost_increase = 25; + SET.bomb_cost = Math.floor(SET.bomb_cost + cost_increase); + WIDGETS.bomb_cost.innerHTML = SET.bomb_cost; + } +} +AimBombMode.prototype = new UserInterfaceMode(); + +var aim_bomb = function(x,y) { + attempt_to_enter_ui_mode(new AimBombMode()); +}; + +var PauseMode = function() { + this.name = function() { return "PauseMode" }; + this.can_leave_mode = function(x,y) { + return false; + }; + this.set_up = function() { + this.began_at = millis(); + $('').trigger("PauseMode"); + } + this.tear_down = function() { + var elapsed = millis() - this.began_at; + SET.rendering_groups.forEach(function(group) { + group.forEach(function(member) { + if (member.last) + member.last += elapsed; + }); + }); + } + this.name = function() { return "PauseMode"; }; +}; +PauseMode.prototype = new UserInterfaceMode(); + +var GameOverMode = function() { + this.set_up = function(x,y) { + SET.score += SET.gold; + SET.gold = 0; + $('').trigger("game_over",true); + } + this.name = function() { return "GameOverMode"; }; + this.can_leave_mode = function(x,y) { return false; }; +}; +GameOverMode.prototype = new UserInterfaceMode(); diff --git a/moksha/widgets/misc/ptd/game/util.js b/moksha/widgets/misc/ptd/game/util.js new file mode 100644 index 0000000..26a68a6 --- /dev/null +++ b/moksha/widgets/misc/ptd/game/util.js @@ -0,0 +1,264 @@ +/* Coordinate System + +There are two coordinate systems in effect that need +to be taken into consideration. The first is the pixel +coordinate system, and the second is a coordinate system +formed by a grid of veritical and horizontal lines. +The grid's size is determined by three settings. + +1. *pixels_per_square* determines the number of pixels per grid square. +2. *height* determines the overall height of the board. +3. *width* determines the overall width of the board. + +Thus the board will create as many squares as possible within +the constraints of the height and width that it is given. + +Within the code, positions within the grid coordinate +system are always referred to as (gx,gy) and positions +in the pixel coordinate system are always referred to +as (x,y). This is a very important distinction, and +mixing the two together can cause ample confusion. + +*/ + +/* + General utility functions. + */ +// return a random number (0 <= n <= max) +var random = function(max) { + return Math.floor(Math.random()*(max+1)); +}; + +//given a start point, and end point, and a speed at which to travel, +//return the point that the entity should go to in the next draw +var calc_path = function(x1,y1,x2,y2,speed) { + var ac = y2 - y1; + var bc = x2 - x1; + var ab = Math.sqrt(Math.pow(ac,2) + Math.pow(bc,2)); + var de = (1.0 * speed * ac) / ab; + var be = (1.0 * speed * bc) / ab; + return {y:de,x:be}; +}; + +var dist = function(x1,y1,x2,y2) { + var ac = y2 - y1; + var bc = x2 - x1; + return Math.sqrt(Math.pow(ac,2) + Math.pow(bc,2)); +} + +/* + Coordinate systems utilities. + */ + +// return pixel coordinates of top left corner +// of square at grid coordinates (gx,gy) +var grid_to_pixel = function(gx,gy) { + if (gy == undefined) { + gy = gx.gy; + gx = gx.gx; + } + return {x:gx*SET.pixels_per_square, y:gy*SET.pixels_per_square}; +}; + +// return grid coordinates of square containing pixel +// coordinate (x,y) +var pixel_to_grid = function(x,y) { + if (y == undefined) { + y = x.y; + x = x.x; + } + var grid_x = Math.floor(x / SET.pixels_per_square); + var grid_y = Math.floor(y / SET.pixels_per_square); + return {gx:grid_x, gy:grid_y}; +}; + +// return pixel coordinates for the center of +// square at grid coordinates (gx,gy) +var center_of_square = function(gx,gy) { + if (gy == undefined) { + gy = gx.gy; + gx = gx.gx; + } + var coords = grid_to_pixel(gx,gy); + return {x:coords.x + SET.half_pixels_per_square, + y:coords.y + SET.half_pixels_per_square}; +}; + +/* + Drawing functions. + */ + +// draw a square filling square (gx,gy) +var draw_square_in_grid = function(gx,gy) { + var pos = grid_to_pixel(gx,gy); + rect(pos.x,pos.y,SET.pixels_per_square,SET.pixels_per_square); +} + +// draw a circle filling (gx,gy) +var draw_circle_in_grid = function(gx,gy) { + var pos = grid_to_pixel(gx,gy); + var h = SET.half_pixels_per_square; + var l = SET.pixels_per_square; + ellipse(pos.x+h,pos.y+h,l-1,l-1); +}; + +/* + Various game utility functions. + */ + +var can_build_here = function(gx,gy) { + if ( get_tower_at(gx,gy) != false) return false; + if ((gx == SET.entrance.gx) && (gy == SET.entrance.gy)) return false; + if ((gx == SET.exit.gx) && (gy == SET.exit.gy)) return false; + + return true; +}; + +var get_tower_at = function(gx,gy) { + var cached = SET.grid_cache_at(gx,gy); + if (cached.tower) return cached.tower; + + var towers = SET.rendering_groups[SET.tower_render_level]; + for (var i=0;i<towers.length;i++) { + var tower = towers[i]; + if (tower.gx == gx && tower.gy == gy) { + cached.tower = tower; + return tower; + } + } + return false; +}; + +var get_terrain_at = function(gx,gy) { + var cached = SET.grid_cache_at(gx,gy); + if (cached.terrain) return cached.terrain; + + var squares = SET.rendering_groups[SET.square_render_level]; + for (var i=0;i<squares.length;i++) { + var square = squares[i]; + if (square.gx == gx && square.gy == gy) { + cached.terrain = square; + return square; + } + } + return; +} + +var get_creep_nearest = function(x,y,sensitivity) { + if (!sensitivity) sensitivity = 10; + var creeps = SET.rendering_groups[SET.creep_render_level]; + var len = creeps.length; + var nearest_creep; + var distance = sensitivity; + for (var i=0;i<len;i++) { + var creep = creeps[i]; + var d = dist(x,y,creep.x,creep.y); + if (d < distance) { + distance = d; + nearest_creep = creep; + } + } + return (distance < sensitivity) ? nearest_creep : undefined; +} + +// Object.extend borrowed from Prototype javascript library. +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +}; + +// Pretty-printing of objects +var pp = function(obj, depth) { + if (depth == undefined) depth = 4; + depth -= 1; + if (depth <= 0) + return '' + obj; + if (obj instanceof Array) { + var str = "["; + obj.forEach(function(i){ + str += pp(i,depth) + ", "; + }); + return str + "]"; + } + if (obj instanceof String) + return '"'+str+'"'; + if (obj instanceof Object){ + var str="{"; //variable which will hold property values + for(prop in obj){ + if (prop == "ancestor") + depth = 0; + str+= pp(prop,depth) + ":" + pp(obj[prop],depth) +", "; + } + return str + "}"; + } + + + return '' + obj; + + +} + +var log = function(label, thing) { + if (thing == undefined) + $('#log').append(label + "<br/>"); + else + $('#log').append(label + ": " + pp(thing) + "<br/>"); +} + + +Array.prototype.equals = function(testArr) { + if (this.length != testArr.length) return false; + for (var i = 0; i < testArr.length; i++) { + if (this[i].equals) { + if (!this[i].equals(testArr[i])) return false; + } + if (this[i] != testArr[i]) return false; + } + return true; +} + +var insert_sorted = function(array, value, sortKey) { + var vkey = sortKey(value); + var min=0; + var max=array.length; + var mid=-1; + while(true){ + if (max<=min) { + break; + } + mid = Math.floor((max+min)/2); + if (mid >= array.length || mid < 0) { + log("outofbounds in insert sorted"); + break; + } + if (vkey <= sortKey(array[mid])) + max = mid-1; + else + min = mid+1; + } + mid = Math.floor((max+min)/2); + if (array[mid]) + if (vkey > sortKey(array[mid])) + mid += 1; + mid = Math.max(0,mid); + + var result = array.slice(0,mid).concat([value]).concat(array.slice(mid)) +// log("inserting", [mid,vkey,array.map(sortKey), result.map(sortKey)]); +// var rm = result.map(sortKey); +// if (!rm.equals(rm.slice().sort(function(a,b){return a-b}))) +// log("insert_sorted failed inserting",[vkey,rm]); + return result; +} + +//moves the given object towards the target at speed +//also ensures that the given object doesn't go outside of the bounds +//of the map +var move_towards = function(obj, x,y,tx,ty,speed) { + var path = calc_path(x,y,tx,ty,speed); + obj.x += path.x; + obj.y += path.y; + obj.x = Math.max(0, Math.min(SET.width , obj.x)); + obj.y = Math.max(0, Math.min(SET.height, obj.y)); +} \ No newline at end of file diff --git a/moksha/widgets/misc/ptd/game/weapons.js b/moksha/widgets/misc/ptd/game/weapons.js new file mode 100644 index 0000000..a591abf --- /dev/null +++ b/moksha/widgets/misc/ptd/game/weapons.js @@ -0,0 +1,398 @@ +var CircleZone = function(x,y,r) { + var cz = new Object(); + Object.extend(cz, InertDrawable); + var d = 2*r; + cz.color = SET.killzone_color; + cz.draw = function() { + fill(this.color); + stroke(255); + ellipse(x,y,d,d); + }; + return cz +} + +var KillZone = function(x,y,r) { + var kz = new CircleZone(x,y,r); + assign_to_depth(kz, SET.killzone_render_level); + return kz; +}; + +var BuildRadius = function(x,y,r) { + var br = KillZone(x,y,r); + assign_to_depth(br, SET.build_zone_render_level); + return br; +}; + +var MissileRadius = function(x,y,r) { + var mr = KillZone(x,y,r); + mr.color = color(0, 40,40,0.5); + return mr; +} + +var Tower = function(settings) { + var tower = GridSquare(settings.gx,settings.gy,settings.color); + Object.extend(tower, settings); + // note, range is in terms of grid squares + // and is calculated from center of tower + tower.set_range = function(range) { + tower.range = range; + tower.prange = range * SET.pixels_per_square; + }; + tower.account_for_terrain = function() { + var terrain = get_terrain_at(this.gx,this.gy); + this.damage = this.damage * terrain.tower_damage_modifier; + this.set_range(this.range * terrain.tower_range_modifier); + this.reload_rate = this.reload_rate * terrain.tower_frequency_modifier; + }; + tower.set_range(3.5); + tower.damage = 5.0; + tower.attack = function(creep) {}; + var mid = center_of_square(tower.gx,tower.gy); + tower.x_mid = mid.x; + tower.y_mid = mid.y; + tower.fired_at = 0; + tower.reload_rate = 1000; + tower.weapon_ready = function() { + if (SET.now - tower.fired_at > tower.reload_rate) { + tower.fired_at = SET.now; + return true; + } + return false; + }; + tower.update = function() { + var creeps = SET.rendering_groups[SET.creep_render_level]; + if (creeps.length == 0) return; + var closest_creep; + var closest_distance; + creeps.forEach(function(creep) { + var distance = dist(tower.x_mid,tower.y_mid,creep.x,creep.y); + if (distance < tower.prange) { + if (!closest_creep) { + closest_creep = creep; + closest_distance = distance; + } + else { + if (distance < closest_distance) { + closest_creep = creep; + closest_distance = distance; + } + } + } + }); + if (closest_creep && tower.weapon_ready() == true) + tower.attack(closest_creep); + } + tower.sale_value = 50; + tower.sell = function() { + SET.gold += Math.floor(this.sale_value * 0.75); + this.is_dead = function() { return true; }; + SET.grid_cache_at(this.gx,this.gy).tower = undefined; + + unselect(); + } + tower.display_stats = function() { + WIDGETS.tower_type.innerHTML = this.type; + WIDGETS.tower_range.innerHTML = this.range; + WIDGETS.tower_damage.innerHTML = this.damage; + WIDGETS.tower_rate.innerHTML = this.reload_rate; + WIDGETS.tower_sell_button.innerHTML = "Sell tower for " + Math.floor(this.sale_value * 0.75) + " gold!"; + WIDGETS.tower_upgrade_button.innerHTML = "<u>U</u>pgrade for " + Math.floor(this.upgrade_cost) + " gold!"; + + WIDGETS.tower_upgrade_button.onclick = function() { + tower.upgrade(); + } + WIDGETS.tower_sell_button.onclick = function() { + tower.sell(); + reset_pathfinding(); + } + WIDGETS.tower.style.display = "block"; + }; + tower.draw = function() { + noStroke(); + fill(this.color); + draw_circle_in_grid(this.gx,this.gy); + } + assign_to_depth(tower, SET.tower_render_level); + return tower; +}; + +var MissileTower = function(gx,gy) { + var mt = Tower({gx:gx,gy:gy,color:color(250,150,50)}); + mt.type = "Missile Tower"; + mt.damage = 5000; + mt.upgrade_cost = 100; + mt.sale_value = 100; + mt.set_range(5.5); + mt.reload_rate = 2000; + mt.attack = function(creep) { + assign_to_depth(Missile(this,creep),SET.bullet_render_level); + } + mt.upgrade = function() { + if (SET.gold >= this.upgrade_cost) { + SET.gold -= this.upgrade_cost; + this.sale_value = Math.floor(this.sale_value + this.upgrade_cost); + this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5); + this.damage = Math.floor(this.damage * 2.5); + this.set_range(this.range + 0.5); + + unselect(); + SET.state = new TowerSelectMode(); + SET.state.set_up(this.x_mid,this.y_mid); + } + else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more."); + } + mt.account_for_terrain(); + return mt; +} + +var LaserTower = function(gx,gy) { + var lt = Tower({gx:gx,gy:gy,color:color(90,150,50)}); + lt.type = "Laser Tower"; + lt.attack = function(creep) { + assign_to_depth(Laser(this,creep),SET.bullet_render_level); + }; + lt.upgrade_cost = 25; + lt.sale_value = 13; + lt.upgrade = function() { + if (SET.gold >= this.upgrade_cost) { + SET.gold -= this.upgrade_cost; + this.sale_value = Math.floor(this.sale_value + this.upgrade_cost); + this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5); + this.damage = Math.floor(this.damage * 2.0); + this.set_range(this.range + 0.25); + this.reload_rate = this.reload_rate - 10; + + unselect(); + SET.state = new TowerSelectMode(); + SET.state.set_up(this.x_mid,this.y_mid); + } + else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more."); + } + lt.damage = 10; + lt.set_range(4); + lt.reload_rate = 250; + lt.account_for_terrain(); + return lt; +}; + +var CannonTower = function(gx,gy) { + var lt = Tower({gx:gx,gy:gy,color:color(100,120,140)}); + lt.type = "Cannon Tower"; + lt.attack = function(creep) { + assign_to_depth(CannonBall(this,{x:creep.x, y:creep.y, hp:1}),SET.bullet_render_level); + }; + lt.upgrade_cost = 75; + lt.sale_value = 50; + lt.upgrade = function() { + if (SET.gold >= this.upgrade_cost) { + SET.gold -= this.upgrade_cost; + this.sale_value = Math.floor(this.sale_value + this.upgrade_cost); + this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5); + this.damage = Math.floor(this.damage * 2.0); + this.set_range(this.range + 0.25); + this.reload_rate = this.reload_rate - 10; + + unselect(); + SET.state = new TowerSelectMode(); + SET.state.set_up(this.x_mid,this.y_mid); + } + else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more."); + } + lt.damage = 100; + lt.set_range(4); + lt.reload_rate = 1000; + lt.account_for_terrain(); + return lt; +}; + +var GatlingTower = function(gx,gy) { + var gt = Tower({gx:gx,gy:gy,color:color(250,250,50)}); + gt.type = "Gatling Tower"; + gt.damage = 50; + gt.upgrade_cost = 25; + gt.sale_value = 50; + gt.set_range(3.5); + + gt.reload_rate = 100; + gt.shots_per_volley = 12; + gt.shots_left_in_volley = gt.shots_per_volley; + gt.pause_after_volley = 2000; + gt.finish_reload_at = 0; + gt.reloading = false; + gt.fire_next_at = 0; + + gt.weapon_ready = function() { + if (gt.reloading && gt.finish_reload_at < SET.now) { + gt.shots_left_in_volley = gt.shots_per_volley; + gt.reloading = false; + } + if (!gt.reloading && gt.fire_next_at < SET.now) { + return true; + } + return false; + }; + + gt.attack = function(creep) { + assign_to_depth(Bullet(this,creep),SET.bullet_render_level); + gt.shots_left_in_volley--; + gt.fire_next_at = SET.now + gt.reload_rate; + if (gt.shots_left_in_volley < 1) { + gt.reloading = true; + gt.finish_reload_at = SET.now + gt.pause_after_volley; + } + } + + gt.upgrade = function() { + if (SET.gold >= this.upgrade_cost) { + SET.gold -= this.upgrade_cost; + this.sale_value = Math.floor(this.sale_value + this.upgrade_cost); + this.upgrade_cost = Math.floor(this.upgrade_cost * 1.5); + this.damage = Math.floor(this.damage * 2.5); + this.set_range(this.range + 0.5); + this.reload_rate = Math.floor(this.reload_rate * 0.95); + unselect(); + SET.state = new TowerSelectMode(); + SET.state.set_up(this.x_mid,this.y_mid); + } + else error("You don't have enough gold to upgrade, you need " + (this.upgrade_cost - SET.gold) + " more."); + } + gt.account_for_terrain(); + return gt; +} + +var Weapon = function(tower,target) { + var w = new Object(); + w.x = tower.x_mid; + w.y = tower.y_mid; + w.target = target; + w.tower = tower; + w.proximity = 7; + w.damage = tower.damage; + w.last = millis(); + w.impact = function(target) { + this.is_dead = function() { return true; }; + target.hp -= this.damage; + } + w.update = function() { + var distance = dist(this.x,this.y,this.target.x,this.target.y); + if (distance < this.proximity) { + this.impact(this.target); + } + else { + var elapsed = 1.0 * (SET.now - this.last); + var speed = this.speed * (elapsed/1000); + this.last = SET.now; + move_towards(this, this.x,this.y,target.x,target.y,this.speed); + } + } + w.is_dead = function() { + if (!target || target.hp <= 0) return true; + return false; + }; + return w; +}; + +var Bullet = function(tower, target) { + var b = new Object(); + Object.extend(b, Weapon(tower,target)); + b.size = 5; + b.color = color(255,255,255); + b.fill_color = color(100,255,0); + b.speed = 8; + b.damage = tower.damage; + b.proximity = 10; + b.draw = function() { + stroke(b.color); + fill(b.fill_color); + ellipse(this.x,this.y,this.size,this.size); + } + return b; +} + +var CannonBall = function(tower, target) { + var c = new Object(); + Object.extend(c, Weapon(tower,target)); + c.midpoint = {x:Math.floor((c.x + target.x)/2.0), y:Math.floor((c.y + target.y) / 2.0)}; + c.middist = dist(c.x, c.y, c.midpoint.x, c.midpoint.y); + c.min_size = 8 + c.size_variance = 4; + c.color = color(0,0,0); + c.fill_color = color(50,50,50); + c.speed = 8; + c.damage = tower.damage; + c.proximity = 25; + c.splash_range = 50.0; + c.draw = function() { + var percent_to_apex = ((this.middist - dist(this.x, this.y, this.midpoint.x, this.midpoint.y)) / this.middist); + size = ((1 - Math.pow(1 - percent_to_apex, 2)) * this.size_variance) + this.min_size; + log("drawing cannonball", size); + stroke(this.color); + fill(this.fill_color); + ellipse(this.x,this.y,size,size); + }; + c.impact = function(target) { + this.is_dead = function() { return true; }; + var creeps = SET.rendering_groups[SET.creep_render_level]; + var l = creeps.length; + var range = Math.floor(this.splash_range); + for (var i=0;i<l;i++) { + var creep = creeps[i]; + var d = Math.floor(dist(this.x,this.y,creep.x,creep.y)); + if (d <= range) { + creep.hp -= this.damage; + } + } + }; + + return c; +}; + +var Missile = function(tower,target) { + var m = new Object(); + Object.extend(m, Weapon(tower,target)); + m.size = 10; + m.color = color(255,0,0); + m.fill_color = color(250,50,50); + m.speed = 8; + m.damage = tower.damage; + m.proximity = 20; + m.is_dead = function() { + if (!this.target || this.target.hp <= 0) { + this.target = get_creep_nearest(this.x,this.y,100); + //log("new target: " + pp(this.target)); + } + if (!this.target) return true; + return false; + } + + m.draw = function() { + stroke(m.color); + fill(m.fill_color); + var mx = this.x; + var my = this.y; + var size = this.size; + var tx = this.target.x; + var ty = this.target.y; + var tth = Math.atan((ty-my)/(tx-mx)); + var angle = 2.35619449; // 135 degrees in radians + triangle(mx,my, + mx+size * Math.cos(tth - 2.35619449), my+size * Math.sin(tth + 2.35619449), + mx+size * Math.cos(tth + 2.35619449), my+size * Math.sin(tth - 2.35619449)); + } + return m; +}; + +var Laser = function(tower,target) { + var l = new Object(); + Object.extend(l, Weapon(tower,target)); + l.tail = 20; // length of laser's graphic + l.color = color(0,0,255); + l.speed = 10; + l.proximity = 10; + l.draw = function() { + var path = calc_path(l.x,l.y,tower.x_mid,tower.y_mid,l.tail); + stroke(l.color); + line(l.x,l.y,l.x+path.x,l.y+path.y); + } + return l; +}; diff --git a/moksha/widgets/misc/ptd/ptd.py b/moksha/widgets/misc/ptd/ptd.py new file mode 100644 index 0000000..baebcef --- /dev/null +++ b/moksha/widgets/misc/ptd/ptd.py @@ -0,0 +1,31 @@ +# Processed Tower Defense Widget + +from tw.api import Widget, CSSLink, JSLink +from tw.jquery.ui import effects_core_js, effects_highlight_min_js +from tw.jquery.processing import processing_js + +modname = __name__ + +jsfprocessing_js = JSLink(filename='static/jsfprocessing.js', + javascript=[processing_js], + modname=modname) + +# lulz +konami = JSLink(filename='static/konami.js', modname=modname) + +class ProcessedTowerDefense(Widget): + name = 'Processed Tower Defense' + hidden = True + template = 'mako:moksha.widgets.misc.ptd.templates.ptd' + css = [CSSLink(filename='static/style.css', modname=modname),] + javascript = [ + processing_js, jsfprocessing_js, + effects_core_js, effects_highlight_min_js, + JSLink(filename='game/creep_waves.js', modname=modname), + JSLink(filename='game/terrain.js', modname=modname), + JSLink(filename='game/util.js', modname=modname), + JSLink(filename='game/creeps.js', modname=modname), + JSLink(filename='game/ui_modes.js', modname=modname), + JSLink(filename='game/weapons.js', modname=modname), + JSLink(filename='game/ptd.js', modname=modname), + ] diff --git a/moksha/widgets/misc/ptd/static/jsfprocessing.js b/moksha/widgets/misc/ptd/static/jsfprocessing.js new file mode 100644 index 0000000..f663e8d --- /dev/null +++ b/moksha/widgets/misc/ptd/static/jsfprocessing.js @@ -0,0 +1,101 @@ +var GLOBAL_PROCESSING; +function set_canvas(id) { + var canvas = document.getElementById(id); + GLOBAL_PROCESSING = Processing(canvas); +} + +function size(height, width) { + GLOBAL_PROCESSING.size(height, width); +} +function stroke(color) { + GLOBAL_PROCESSING.stroke(color); +} +function background(color) { + GLOBAL_PROCESSING.background(color); +} + +function line(x1, y1, x2, y2) { + GLOBAL_PROCESSING.line(x1, y1, x2, y2); +} + +var draw = function() {}; // stub to replace + +function frameRate(rate) { + var interval = 1000.00 / rate; + setInterval(draw, interval); +} + +function height() { + return GLOBAL_PROCESSING.height; +} + +function width() { + return GLOBAL_PROCESSING.width; +} + +function rect(x,y,width,height) { + return GLOBAL_PROCESSING.rect(x,y,width,height); +} + +function ellipse(x,y,width,height) { + return GLOBAL_PROCESSING.ellipse(x,y,width,height); +} + +function triangle(x1,y1,x2,y2,x3,y3) { + return GLOBAL_PROCESSING.triangle(x1,y1,x2,y2,x3,y3); +} + +function fill(color) { + return GLOBAL_PROCESSING.fill(color); +} + +var color = function(r,g,b,a) { + if (!a) + return "rgb(" + r + "," + g + "," + b + ")"; + else + return "rgba(" + r + "," + g + "," + b + "," + a +")"; +}; + +function translate(width, height) { + return GLOBAL_PROCESSING.translate(width, height); +} + +function noFill() { + return GLOBAL_PROCESSING.noFill(); +} + +function noStroke() { + return GLOBAL_PROCESSING.noStroke(); +} + +function mouse_pos() { + return {x:GLOBAL_PROCESSING.mouseX, y:GLOBAL_PROCESSING.mouseY}; +} + +function previous_mouse_pos() { + return {x:GLOBAL_PROCESSING.pmouseX, y:GLOBAL_PROCESSING.pmouseY}; +} + +function mousePressed(func) { + GLOBAL_PROCESSING.mousePressed = func; +} + +function mouseReleased(func) { + GLOBAL_PROCESSING.mouseReleased = func; +} + +function mouseMoved(func) { + GLOBAL_PROCESSING.mouseMoved = func; +} + +function mouseReleased(func) { + GLOBAL_PROCESSING.mouseDragged = func; +} + +function millis() { + return GLOBAL_PROCESSING.millis(); +} + +function initProcessing() { + GLOBAL_PROCESSING.init(); +} diff --git a/moksha/widgets/misc/ptd/static/konami.js b/moksha/widgets/misc/ptd/static/konami.js new file mode 100644 index 0000000..7484c9a --- /dev/null +++ b/moksha/widgets/misc/ptd/static/konami.js @@ -0,0 +1,10 @@ +if ( window.addEventListener ) { + var kkeys = [], konami = "38,38,40,40,37,39,37,39,66,65"; + window.addEventListener("keydown", function(e){ + kkeys.push( e.keyCode ); + if ( kkeys.toString().indexOf( konami ) >= 0 ) { + window.location = '/widgets/ptd'; + kkeys = []; + } + }, true); +} diff --git a/moksha/widgets/misc/ptd/static/style.css b/moksha/widgets/misc/ptd/static/style.css new file mode 100644 index 0000000..88ff585 --- /dev/null +++ b/moksha/widgets/misc/ptd/static/style.css @@ -0,0 +1,171 @@ +#tower_defense { + float:left; +} + +/* + From the always helpful article on styling buttons. + http://particletree.com/features/rediscovering-the-button-element/ + */ + +button{ + margin:0 7px 0 0; + background-color:#f5f5f5; + border:1px solid #dedede; + border-top:1px solid #eee; + border-left:1px solid #eee; + font-size:100%; + line-height:110%; + text-decoration:none; + font-weight:bold; + color:#565656; + cursor:pointer; + padding:5px 10px 6px 7px; /* Links */ +} +button:hover { + background-color:#dff4ff; + border:1px solid #c2e1ef; + color:#336699; +} +button:active{ + background-color:#6299c5; + border:1px solid #6299c5; + color:#fff; +} + +button.active_mode { + background-color:#6299c5; + border:1px solid #6299c5; + color:#fff; +} + +div#game { + background-color: #888; + padding-left: 10px; + padding-top: 20px; + padding-bottom: 20px; + overflow: auto; +} + +#game div { + overflow:auto +} + +#menu { + float: left; +} + +#top_controls .item { + padding-right: 10px; +} + +#middle { + overflow: auto; +} + +#bottom_controls { + padding-bottom:10px; + padding-top:5px; + width: 100%; +} + +#game_over { + font-size: 150%; + background-color: #000; + color: #f73; +} + +.error { + background-color: #000; + color: #f73; +} + +div#side { + float: left; +} + +#tower { + display: none; +} + +#creep { + display: none; +} + +#side table { + margin-left: 10px; + margin-top: 10px; + border: solid 1px black; +} +#side .message_area { + margin-left: 10px; + margin-top: 10px; + border: solid 1px black; +} +#logging_button { + display: none; +} + +.hotkey { + text-decoration: underline; +} + +#help { + background: white; + margin-top: 25px; + margin-left: 20px; + padding-left: 30px; + padding-right: 30px; + width: 500px; + height: 400px; + position: absolute; + z-index: 1000; + display: none; + border: 3px solid black; +} + + +#help-sections div { + display: none; +} + +#help-sections div.visible { + display: block; +} + +#help-headers { + padding: 10px; + border-bottom: 2px solid black; +} + +a.section { + margin-left: 5px; + margin-right: 5px; + padding-left: 5px; + padding-right: 5px; + text-decoration: none; + color: black; +} + +a.section:hover { + color: #AAA; +} +a.section.active { color: #2259a5; font-weight: bold;} +a.section.active:hover { color: #2259a5;} + +#help .missile-tower { color: rgb(250,150,50); } +#help .laser-tower { color: rgb(90,150,50); } +#help .cannon-tower { color: rgb(100,120,140); } +#help .gatling-tower { color: rgb(250,250,50); } + +#help .normal-creep { color: rgb(255,255,0);} +#help .quick-creep {color: rgb(200,150,50);} +#help .strong-creep {color: rgb(0,255,255);} +#help .boss-creep {color: rgb(255,100,150);} + +#help .neutral-terrain {color: rgb(200,200,200);} +#help .mountain-terrain {color: rgb(228,51,51);} +#help .water-terrain {color: rgb(78,150,236);} +#help .power-plant-terrain {color: rgb(189,194,78);} + +#help .bomb {color: rgb(100,120,140);} +#help .nuke {color: rgb(255,70,30);} diff --git a/moksha/widgets/misc/ptd/templates/__init__.py b/moksha/widgets/misc/ptd/templates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/moksha/widgets/misc/ptd/templates/ptd.mak b/moksha/widgets/misc/ptd/templates/ptd.mak new file mode 100644 index 0000000..bfc9f48 --- /dev/null +++ b/moksha/widgets/misc/ptd/templates/ptd.mak @@ -0,0 +1,319 @@ +# -*- coding: utf-8 -*- +<div class="container"> + +<div id="game_over"></div> + +<div id="game"> + <div id="top_controls"> + <span class='item'> Lives: <span id="lives">20</span></span> + <span class='item'> Score: <span id="score">0</span></span> + <span class='item'> Gold: <span id="gold">0</span></span> + <span class='item'> Wave: <span id="wave">1</span></span> + <span class='item'> Creep Variety: <span id="creep_variety"></span></span> + <span class='item'> Next Wave in <span id="till_next_wave"></span> seconds</span> + </div> + <div id="help"> + + + <div id="help-headers"> + <span><a class="section active" href="#help-gameplay">Gameplay</a></span> + <span><a class="section" href="#help-towers">Towers</a></span> + <span><a class="section" href="#help-creeps">Creeps</a></span> + <span><a class="section" href="#help-terrain">Terrain</a></span> + <span><a class="section" href="#help-bomb">Bombs & Nukes</a></span> + </div> + <div id="help-sections"> + <div class="visible" id="help-gameplay"> + <p> Processed Tower Defense is a strategy game where you try to defeat waves of dangerous monsters before they reach your tower. Of course, its less of a tower and more of a blueish square on the right side of the screen, but the idea stands. </p> + <p> Monsters appear on the only colorful square on the far left edge of the map, sprint towards the only colorful square on the far right edge of the map. Each time a monster reaches your tower, you lose one life. Lose all of your lives and the game ends. </p> + <p> You start out with a small treasury of gold, and each time you defeat a creep you receive a bit more gold to aid in your valiant defense of the lame blue squa... I mean... your tower. You also receive a few more points to your score when you defeat a creep. While gold can be redeemed for more powerful towers, score can only be redeemed as social capital among fellow PTD players, and thus could be fairly described as both invaluable and worthless. </p> + </div> + <div id="help-towers"> + <p> Towers are your first and last line of defense against creeps. Except for the bomb and the nuke, but thats not the point right now. We're talking about towers, okay? Keep on task, won't ya? </p> + <ul> + <li><strong class='missile-tower'>Missile Towers</strong> – slow-firing towers with long range and the gentle caress of a freight truck.</li> + <li><strong class='cannon-tower'>Cannon Towers</strong> – potent beasts whose arcing balls of destruction cause splash damage</li> + <li><strong class='gatling-tower'>Gatling Towers</strong> – unleash a relentless fury of bullets... until they pause to reload</li> + <li><strong class='laser-tower'>Laser Towers</strong> – the circular reincarnation of bland reliability: they shoot blue lines at a high rate, and nothing else</li> + </ul> + <p> Towers all have another helpful characteristic: they block the paths of creeps. This lets you build complex mazes in the hope that the creeps will become dizzy and stop for a few moments to recover over a nice cup of tea. At the bare minimum you'll get to shoot at them for longer. </p> + </div> + <div id="help-creeps"> + <p> Creeps are the evil scourge which long to plaster the sickening <strong>Game Over</strong> message at the top of your screen. Resisting them is your calling, your purpose, your afternoon you were supposed to spend doing laundry.</p> + <ul> + <li><strong class='normal-creep'>Normal</strong> creeps: You will know these creeps well, and will prosper by ending their drab, boring existences</li> + <li><strong class='quick-creep'>Quick</strong> creeps arrive every third wave. These creeps move quickly, but their smaller bodies can take less damage</li> + <li><strong class='strong-creep'>Strong</strong> creeps plow through your territory every five waves. They're slow, but extremely hearty.</li> + <li><strong class='boss-creep'>Boss</strong> creep: once in a blue moon, one of these warlords appears and lays waste to your defenses with its absurd hitpoints and size.</li> + </ul> + <p> Each of those categories of creeps can also have one additional behavior. Some creeps are very slow crossing water, some climb mountains at shocking speeds, and some even fly over your towers while mocking the effectiveness of your intricate designs.</p> + </div> + <div id="help-terrain"> + <p> Each square on the board is a certain type of terrain. Terrain is randomly assigned each time the game is played, and bestows certain effects upon towers and creeps inside of them. </p> + <ul> + <li> <strong class='neutral-terrain'>Neutral</strong> terrain is the most common terrain, and doesn't do anything. </li> + <li> <strong class='water-terrain'>Water</strong> terrain slows most creeps down.</li> + <li> <strong class='mountain-terrain'>Mountain</strong> terrain slows creeps down, and gives towers a range bonus. </li> + <li> <strong class='power-plant-terrain'> Power plant </strong> terrain makes creep zip along at double speed, but will also double the damage of any tower built there. </li> + </ul> + </div> + <div id="help-bomb"> + <p> The <strong class='bomb'>Bomb</strong> is the first of two last resort weapons at your disposal. You have an unlimited supply, but they get a bit more expensive with each passing level. Will severely damage all creeps in its radius (dealing 75% of their max hitpoints), but won't come cheap. </p> + <p> The <strong class='nuke'>Nuke</strong> is the last resort weapon of last resort weapons. It will destroy all creeps on the screen, but has two drawbacks. First, you won't recieve any loot from creeps destroyed this way. Second, you only have a limited supply and have no way to replenish that supply once they are exhausted. </p> + </div> + </div> + + </div> + + <div id="middle"> + <canvas id='tower_defense' width="600" height="400"></canvas> + + <div id="side"> + <div id="controls"> + <table> + <tr> + <td> <button id='laser_button' class='mode_button' onclick="build_laser_tower();" accesskey="L">Build <span class='hotkey'>L</span>aser Tower - 25 Gold</button> </td> + </tr> + <tr> + <td> <button id='gatling_button' class='mode_button' onclick="build_gatling_tower();"> Build <span class='hotkey'>G</span>attling Tower - 50 Gold</button></td> + </tr> + <tr> + <td> <button id='cannon_button' class='mode_button' onclick="build_cannon_tower();" accesskey="M">Build <span class='hotkey'>C</span>annon Tower - 75 Gold</button> </td> + </tr> + <tr> + <td> <button id='missile_button' class='mode_button' onclick="build_missile_tower();" accesskey="M">Build <span class='hotkey'>M</span>issile Tower - 100 Gold</button> </td> + </tr> + <tr> + <td> <button id='bomb_button' class='mode_button' onclick="aim_bomb();" accesskey="S">Drop <span class='hotkey'>B</span>omb - <span id="bomb_cost">50</span> Gold</button></td> + </tr> + <tr> + <td> <button onclick="nuke_creeps();" accesskey="N"> Launch <span class='hotkey'>N</span>uke - <span id="nukes_left"> 3 left </span></button></td> + </tr> + </table> + </div> + + <div id="tower"> + <table> + <tr><td></td><td> <em>Tower Details</em> </td></tr> + <tr><td> Type: </td><td id="tower_type"></td></tr> + <tr><td> Range: </td><td id="tower_range"></td></tr> + <tr><td> Damage: </td><td id="tower_damage"></td></tr> + <tr><td> Firing Rate: </td><td id="tower_rate"></td></tr> + <tr><td><button id="tower_sell_button"></button></td></tr> + <tr><td><button id="tower_upgrade_button"><span class='hotkey'>U</span>pgrade!</button></td></tr> + </table> + </div> + <div id="creep"> + <table> + <tr><td></td><td> <em> Creep Details </em></td></tr> + <tr><td> Type: </td><td id="creep_type"></td></tr> + <tr><td> Hp: </td><td id="creep_hp"></td></tr> + <tr><td> Value: </td><td id="creep_value"></td></tr> + </table> + </div> + <div class='error message_area'></div> + <div class='message message_area'></div> + </div> + </div> + + <div id="bottom_controls"> + <button id='pause_button' class='mode_button' onclick="pause();">Pause</button> + <button id='reset_button' onclick="reset_game();">Reset Game</button> + <button onclick="spawn_wave();">Spawn Next <span class='hotkey'>W</span>ave</button> +<!-- <button id='mute_button' onclick="mute();">Mute</button> --> + <button id='help_button' onclick="toggle_help();"><span class='hotkey'>H</span>elp</button> + <button id='logging_button' onclick='toggle_logging();' class='active_mode'>Stop <span class='hotkey'>D</span>ebugging</button> + </div> +</div> + +<h4>Hotkeys:</h4> +<ul> + <li>[space] – Pause/Resume</li> + <li>[esc] – Cancel Tower/Missile</li> + <li>H – Help!</li> + <li>L – Build laser tower</li> + <li>M – Build missile tower</li> + <li>G – Build gatling tower</li> + <li>C – Build cannon tower</li> + <li>B – Drop Bomb</li> + <li>N – Launch Nuke</li> + <li>W – Spawn Next Wave</li> + <li>U – Upgrade Selected Tower</li> +</ul> + +<script type="text/javascript" charset="utf-8"> + /* initialization */ + $(document).ready(function() { + start_tower_defense(); + }) + + + /* Hotkeys! */ + special_keys = { + 27: 'esc', 9: 'tab', 32:'space', 13: 'return', 8:'backspace', 145: 'scroll', 20: 'capslock', + 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',35:'end', 33: 'pageup', 16: 'shift', + 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down', 112:'f1',113:'f2', 114:'f3', + 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8', 120:'f9', 121:'f10', 122:'f11', 123:'f12'}; + + /* Modifier keys */ + var modifierkeys = {}; + var shift_down = false; + + //extract hotkeys from the DOM + var hotkeys = {}; + $('button .hotkey').each(function(){ + //this is bass ackwards, but I got type errors passing around the native click method + var button = this.parentNode; + hotkeys[$(this).html().toUpperCase()] = function() {button.click()}; + }); + + //hotkeys that aren't in the dom + hotkeys["space"] = pause; + hotkeys["esc"] = unselect; + hotkeys['Z'] = function() {$('#log').empty()}; + hotkeys['R'] = function() {if (SET.state.name() == "GameOverMode") reset_game();} + + //modifiers to be called on keydown and keyup + modifierkeys["shift"] = function() { shift_down = !shift_down; }; + + $(document).bind("keydown", function(e) { + // if the user is holding down ctrl or cmd, let the browser handle it + if (e.metaKey) return true; + var key = special_keys[e.keyCode] || String.fromCharCode(e.keyCode); + if (key in hotkeys){ + hotkeys[key](); + return false; + } + if (key in modifierkeys){ + modifierkeys[key](); + return false; + } + return true; + }); + + $(document).bind("keyup", function(e) { + if (e.metaKey) return true; + var key = special_keys[e.keyCode] || String.fromCharCode(e.keyCode); + if (key in modifierkeys){ + modifierkeys[key](); + return false; + } + return true; + }); + + + /* Toggle buttons along the bottom */ + + // all of this is really a prime candidate for some cleanup + // so much dupiclation and so many global variables for such + // simple behavior + + var paused = false; + function pause() { + paused = !paused; + pause_resume(); + $('#pause_button').html(paused ? "Resume" : "Pause"); + } + function mute() { + mute_unmute(); + $('#mute_button').html(muted ? "Unmute" : "Mute"); + } + var logging = true; + var prim_log = log; + function toggle_logging() { + logging = !logging; + + if (logging) + log = prim_log; + else + log = function(){}; + $("#logging_button").toggleClass("active_mode").html(logging? "Stop <span class='hotkey'>D</span>ebugging" : 'Start <span class="hotkey">D</span>ebugging'); + } + + if (document.location.hash == "#debug") + $('#logging_button').show(); + else{ + toggle_logging() + $('#logging_button')[0].onclick = function(){}; + } + + var getIdFromURL = function(url) { + return url.slice(url.indexOf("#")); + } + $("#help-headers .section").click(function() { + $("#help-sections div").hide(); + $(getIdFromURL(this.href)).show(); + $("#help-headers .section").removeClass("active"); + $(this).addClass("active"); + return false; + }) + + var help_displayed = false; + var toggle_help = function() { + help_displayed = !help_displayed; + if (help_displayed){ + $("#help").show(); + $("#help_button").addClass("active_mode"); + if (!paused) pause(); + } + else { + $('#help').hide(); + $('#help_button').removeClass('active_mode'); + if (paused) pause(); + } + }; + + + + /* illustrating to the user what mode they're in*/ + mode_signifiers = {'BuildLaserTowerMode':'laser_button', 'BuildGatlingTowerMode':'gatling_button', + 'BuildCannonTowerMode':'cannon_button', 'BuildMissileTowerMode':'missile_button', + 'AimBombMode':'bomb_button', 'PauseMode':'pause_button'}; + for (event in mode_signifiers) { + $('').bind(event, function(e) { + $('#'+mode_signifiers[e.type]).addClass('active_mode'); + }); + } + $('').bind('no_mode', function() { + $('.mode_button').removeClass('active_mode'); + }) + + + /* Messages for the player */ + + //Temporary messages are a bit of a pain + var timeToHide = null; + ["error","message"].forEach(function(s){ + $('.'+s).hide(); + $('').bind(s,function(e,message){ + timeToHide = new Date().getTime() + 2500; + var el = $('.'+s); + el.html(message).fadeIn(); + window.setTimeout(function() { + if (new Date().getTime() >= timeToHide) + el.fadeOut(); + }, 3000); + }); + }); + $('#game_over').hide(); + $('').bind('game_over', function(e,over){ + if (over == true){ + log("game over"); + $('#game_over').html("Game Over! Final score: " + $("#score").html()).fadeIn(); + //tempt tempt tempt + for (var i=0; i < 3; i++) + $("#reset_button").effect("highlight",{color:"#f60"},3000); + } + else{ + log("game (re?)started"); + $('#game_over').html("Just once more...").fadeOut(); + } + }); + + /* stub until we pull in sound for reals */ + var play_sound = function(){}; +</script> +<div id="log"></div> +<div id="sfx_dump"></div> + +</div>
commit 308769f819e8322385486bb154c2a6f42de13f1d Merge: a3d9d2f... 60ed1f4... Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 16:18:44 2009 -0500
Merge branch 'master' of git+ssh://git.fedorahosted.org/git/moksha
commit a3d9d2f48f0355ccd9040c9447d3fe72aae0ebe8 Merge: da163c0... 8ca724e... Author: Luke Macken lmacken@redhat.com Date: Tue Feb 3 15:56:17 2009 -0500
Merge branch 'master' of git+ssh://git.fedorahosted.org/git/moksha
commit da163c0687237e006eb792c049d77c7bb8df8e15 Author: Luke Macken lmacken@redhat.com Date: Mon Feb 2 23:56:01 2009 -0500
I added the jQuery UI JSLinks to the tw.query.ui module
diff --git a/moksha/widgets/container/container.py b/moksha/widgets/container/container.py index 3abb547..6fcfd4d 100644 --- a/moksha/widgets/container/container.py +++ b/moksha/widgets/container/container.py @@ -19,24 +19,12 @@ from tw.api import Widget, JSLink, CSSLink from tw.jquery import jquery_js, jQuery
-# @@ put this stuff in the tw.jquery modules - -ui_core_js = JSLink(filename='static/js/ui/ui.core.js', - modname=__name__, javascript=[jquery_js]) -ui_draggable_js = JSLink(filename='static/js/ui/ui.draggable.js', - modname=__name__, javascript=[ui_core_js]) -ui_resizable_js = JSLink(filename='static/js/ui/ui.resizable.js', - modname=__name__, javascript=[ui_core_js]) - -container_js = JSLink(filename='static/js/mbContainer.js', - modname=__name__) -container_css = CSSLink(filename='static/css/mbContainer.css', - modname=__name__) - +container_js = JSLink(filename='static/js/mbContainer.js', modname=__name__) +container_css = CSSLink(filename='static/css/mbContainer.css', modname=__name__)
class MokshaContainer(Widget): template = 'mako:moksha.widgets.container.templates.container' - javascript = [container_js] # , ui_draggable_js, ui_resizable_js] + javascript = [container_js] css = [container_css] options = ['draggable', 'droppable', 'resizable', 'stikynote'] button_options = ['iconize', 'minimize', 'close'] @@ -48,7 +36,6 @@ class MokshaContainer(Widget): content = '' # either text, or a Widget title = 'Moksha Container' skin = 'skin3' # skin[1-7] - #id = 'moksha_container'
# Pixel tweaking width = 400
moksha-commits@lists.fedorahosted.org