start help pages; fixes broken help links
This commit is contained in:
parent
e3146068bc
commit
c226f6200f
@ -576,4 +576,8 @@ div.bottom-reply {
|
|||||||
|
|
||||||
.mt-1 {
|
.mt-1 {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 1rem 0;
|
||||||
}
|
}
|
BIN
data/dk.db
BIN
data/dk.db
Binary file not shown.
@ -3,6 +3,7 @@ package routes
|
|||||||
import (
|
import (
|
||||||
"dk/internal/components"
|
"dk/internal/components"
|
||||||
"dk/internal/database"
|
"dk/internal/database"
|
||||||
|
"dk/internal/helpers"
|
||||||
"dk/internal/helpers/markdown"
|
"dk/internal/helpers/markdown"
|
||||||
"dk/internal/models/forum"
|
"dk/internal/models/forum"
|
||||||
"dk/internal/models/users"
|
"dk/internal/models/users"
|
||||||
@ -15,8 +16,7 @@ import (
|
|||||||
"git.sharkk.net/Sharkk/Sushi/auth"
|
"git.sharkk.net/Sharkk/Sushi/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ThreadData flattened struct for template use
|
type threadData struct {
|
||||||
type ThreadData struct {
|
|
||||||
ID int
|
ID int
|
||||||
Posted int64
|
Posted int64
|
||||||
LastPost int64
|
LastPost int64
|
||||||
@ -34,8 +34,7 @@ type ThreadData struct {
|
|||||||
HasReplies bool
|
HasReplies bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplyData flattened struct for template use
|
type replyData struct {
|
||||||
type ReplyData struct {
|
|
||||||
ID int
|
ID int
|
||||||
Posted int64
|
Posted int64
|
||||||
Author int
|
Author int
|
||||||
@ -46,47 +45,18 @@ type ReplyData struct {
|
|||||||
AuthorClass string
|
AuthorClass string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper methods for ThreadData
|
func (t *threadData) PostedTime() time.Time {
|
||||||
func (t *ThreadData) PostedTime() time.Time {
|
|
||||||
return time.Unix(t.Posted, 0)
|
return time.Unix(t.Posted, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ThreadData) LastPostTime() time.Time {
|
func (t *threadData) LastPostTime() time.Time {
|
||||||
return time.Unix(t.LastPost, 0)
|
return time.Unix(t.LastPost, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper methods for ReplyData
|
func (r *replyData) PostedTime() time.Time {
|
||||||
func (r *ReplyData) PostedTime() time.Time {
|
|
||||||
return time.Unix(r.Posted, 0)
|
return time.Unix(r.Posted, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaginationParams handles common pagination logic
|
|
||||||
type PaginationParams struct {
|
|
||||||
Page int
|
|
||||||
PerPage int
|
|
||||||
Total int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p PaginationParams) Offset() int {
|
|
||||||
return (p.Page - 1) * p.PerPage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p PaginationParams) TotalPages() int {
|
|
||||||
pages := (p.Total + p.PerPage - 1) / p.PerPage
|
|
||||||
if pages < 1 {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p PaginationParams) HasNext() bool {
|
|
||||||
return p.Page < p.TotalPages()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p PaginationParams) HasPrev() bool {
|
|
||||||
return p.Page > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterForumRoutes(app *sushi.App) {
|
func RegisterForumRoutes(app *sushi.App) {
|
||||||
authed := app.Group("/forum")
|
authed := app.Group("/forum")
|
||||||
authed.Use(auth.RequireAuth())
|
authed.Use(auth.RequireAuth())
|
||||||
@ -117,19 +87,19 @@ func validateThread(ctx sushi.Ctx, id int) (*forum.Forum, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get pagination params from request
|
// Helper function to get pagination params from request
|
||||||
func getPaginationParams(ctx sushi.Ctx, perPage int) PaginationParams {
|
func getPagination(ctx sushi.Ctx, perPage int) helpers.Pagination {
|
||||||
page := max(int(ctx.QueryArgs().GetUintOrZero("page")), 1)
|
page := max(int(ctx.QueryArgs().GetUintOrZero("page")), 1)
|
||||||
return PaginationParams{
|
return helpers.Pagination{
|
||||||
Page: page,
|
Page: page,
|
||||||
PerPage: perPage,
|
PerPage: perPage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func index(ctx sushi.Ctx) {
|
func index(ctx sushi.Ctx) {
|
||||||
pagination := getPaginationParams(ctx, 30)
|
pagination := getPagination(ctx, 30)
|
||||||
|
|
||||||
// Get threads with user data
|
// Get threads with user data
|
||||||
var threads []*ThreadData
|
var threads []*threadData
|
||||||
query := `
|
query := `
|
||||||
SELECT f.id, f.posted, f.last_post, f.author, f.parent, f.replies, f.title, f.content,
|
SELECT f.id, f.posted, f.last_post, f.author, f.parent, f.replies, f.title, f.content,
|
||||||
COALESCE(u.username, '[Deleted]') as author_username,
|
COALESCE(u.username, '[Deleted]') as author_username,
|
||||||
@ -145,7 +115,7 @@ func index(ctx sushi.Ctx) {
|
|||||||
err := database.Select(&threads, query, pagination.PerPage, pagination.Offset())
|
err := database.Select(&threads, query, pagination.PerPage, pagination.Offset())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error fetching forum threads: %v", err)
|
log.Printf("Error fetching forum threads: %v", err)
|
||||||
threads = make([]*ThreadData, 0)
|
threads = make([]*threadData, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get last reply info for each thread
|
// Get last reply info for each thread
|
||||||
@ -235,11 +205,11 @@ func showThread(ctx sushi.Ctx) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pagination := getPaginationParams(ctx, 10)
|
pagination := getPagination(ctx, 10)
|
||||||
pagination.Total = thread.Replies
|
pagination.Total = thread.Replies
|
||||||
|
|
||||||
// Get thread with author data
|
// Get thread with author data
|
||||||
var threadData ThreadData
|
var threadData threadData
|
||||||
err := database.Get(&threadData, `
|
err := database.Get(&threadData, `
|
||||||
SELECT f.id, f.posted, f.last_post, f.author, f.parent, f.replies, f.title, f.content,
|
SELECT f.id, f.posted, f.last_post, f.author, f.parent, f.replies, f.title, f.content,
|
||||||
COALESCE(u.username, '[Deleted]') as author_username,
|
COALESCE(u.username, '[Deleted]') as author_username,
|
||||||
@ -259,7 +229,7 @@ func showThread(ctx sushi.Ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get replies with user data
|
// Get replies with user data
|
||||||
var replies []*ReplyData
|
var replies []*replyData
|
||||||
err = database.Select(&replies, `
|
err = database.Select(&replies, `
|
||||||
SELECT f.id, f.posted, f.author, f.title, f.content,
|
SELECT f.id, f.posted, f.author, f.title, f.content,
|
||||||
COALESCE(u.username, '[Deleted]') as author_username,
|
COALESCE(u.username, '[Deleted]') as author_username,
|
||||||
@ -274,7 +244,7 @@ func showThread(ctx sushi.Ctx) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error loading replies for thread %d: %v", id, err)
|
log.Printf("Error loading replies for thread %d: %v", id, err)
|
||||||
replies = make([]*ReplyData, 0)
|
replies = make([]*replyData, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
components.RenderPage(ctx, threadData.Title, "forum/thread.html", map[string]any{
|
components.RenderPage(ctx, threadData.Title, "forum/thread.html", map[string]any{
|
||||||
|
16
internal/routes/help.go
Normal file
16
internal/routes/help.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"dk/internal/components"
|
||||||
|
|
||||||
|
sushi "git.sharkk.net/Sharkk/Sushi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterHelpRoutes(app *sushi.App) {
|
||||||
|
group := app.Group("/help")
|
||||||
|
group.Get("/", guide)
|
||||||
|
}
|
||||||
|
|
||||||
|
func guide(ctx sushi.Ctx) {
|
||||||
|
components.RenderPage(ctx, "Help", "help/guide.html", map[string]any{})
|
||||||
|
}
|
1
main.go
1
main.go
@ -180,6 +180,7 @@ func start(port string) error {
|
|||||||
routes.RegisterTownRoutes(app)
|
routes.RegisterTownRoutes(app)
|
||||||
routes.RegisterFightRoutes(app)
|
routes.RegisterFightRoutes(app)
|
||||||
routes.RegisterForumRoutes(app)
|
routes.RegisterForumRoutes(app)
|
||||||
|
routes.RegisterHelpRoutes(app)
|
||||||
|
|
||||||
app.Get("/assets/*path", sushi.Static(cwd))
|
app.Get("/assets/*path", sushi.Static(cwd))
|
||||||
|
|
||||||
|
190
templates/help/guide.html
Normal file
190
templates/help/guide.html
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
{include "layout.html"}
|
||||||
|
|
||||||
|
{block "content"}
|
||||||
|
<a name="top"></a>
|
||||||
|
<h1>Help</h1>
|
||||||
|
[ <a href="/index.php">Return to the game</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3>Table of Contents</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#intro">Introduction</a></li>
|
||||||
|
<li><a href="#classes">Character Classes</a></li>
|
||||||
|
<li><a href="#intown">In Town</a></li>
|
||||||
|
<li><a href="#exploring">Exploring & Fighting</a></li>
|
||||||
|
<li><a href="#status">Status Panels</a></li>
|
||||||
|
<li><a href="#items">Items & Drops</a></li>
|
||||||
|
<li><a href="#monsters">Monsters</a></li>
|
||||||
|
<li><a href="#spells">Spells</a></li>
|
||||||
|
<li><a href="#levels">Levels</a></li>
|
||||||
|
<li><a href="#credits">Credits</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="intro"></a>Introduction</h3>
|
||||||
|
Firstly, I'd like to say thank you for playing my game. The <i>Dragon Knight</i> game engine is the result of several months of
|
||||||
|
planning, coding and testing. The original idea was to create a web-based tribute to the NES game, <i>Dragon
|
||||||
|
Warrior</i>. In its current iteration, only the underlying fighting system really resembles that game, as almost
|
||||||
|
everything else in DK has been made bigger and better. But you should still recognize bits and pieces as stemming
|
||||||
|
from <i>Dragon Warrior</i> and other RPGs of old.<br><br>
|
||||||
|
This is the first game I've ever written, and it has definitely been a positive experience. It got difficult at
|
||||||
|
times, admittedly, but it was still a lot of fun to write, and even more fun to play. And I hope to use this
|
||||||
|
experience so that if I ever want to create another game it will be even better than this one.<br><br>
|
||||||
|
If you are a site administrator, and would like to install a copy of DK on your own server, you may visit the
|
||||||
|
<a href="http://dragon.se7enet.com/dev.php" target="_new">development site</a> for <i>Dragon Knight</i>. This page
|
||||||
|
includes the downloadable game souce code, as well as some other resources that developers and administrators may
|
||||||
|
find valuable.<br><br>
|
||||||
|
Once again, thanks for playing!<br><br>
|
||||||
|
<i>Jamin Seven</i><br>
|
||||||
|
<i>Dragon Knight creator</i><br>
|
||||||
|
<a href="http://www.se7enet.com" target="_new">My Homepage</a><br>
|
||||||
|
<a href="http://dragon.se7enet.com/dev.php" target="_new">Dragon Knight Homepage</a><br ><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="classes"></a>Character Classes</h3>
|
||||||
|
There are three character classes in the game. The main differences between the classes are what spells you get
|
||||||
|
access to, the speed with which you level up, and the amount of HP/MP/strength/dexterity you gain per level. Below
|
||||||
|
is a basic outline of each of the character classes. For more detailed information about the characters, please
|
||||||
|
view the Levels table at the bottom of this page. Also, note that the outline below refers to the stock class setup
|
||||||
|
for the game. If your administrator has used his/her own class setup, this information may not be accurate.<br><br>
|
||||||
|
<b>@TODO</b>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="intown"></a>In Town</h3>
|
||||||
|
When you begin a new game, the first thing you see is the Town screen. Towns serve four primary functions: healing, buying items,
|
||||||
|
buying maps, and displaying game information.<br><br>
|
||||||
|
To heal yourself, click the "Rest at the Inn" link at the top of the town screen. Each town's Inn has a different price - some towns
|
||||||
|
are cheap, others are expensive. No matter what town you're in, the Inns always serve the same function: they restore your current
|
||||||
|
hit points, magic points, and travel points to their maximum amounts. Out in the field, you are free to use healing spells to restore
|
||||||
|
your hit points, but when you run low on magic points, the only way to restore them is at an Inn.<br><br>
|
||||||
|
Buying weapons and armor is accomplished through the appropriately-named "Buy Weapons/Armor" link. Not every item is available in
|
||||||
|
every town, so in order to get the most powerful items, you'll need to explore some of the outer towns. Once you've clicked the link,
|
||||||
|
you are presented with a list of items available in this town's store. To the left of each item is an icon that represents its type:
|
||||||
|
weapon, armor or shield. The amount of attack/defense power, as well as the item's price, are displayed to the right of the item name.
|
||||||
|
You'll notice that some items have a red asterisk (<span class="highlight">*</span>) next to their names. These are items that come
|
||||||
|
with special attributes that modify other parts of your character profile. See the Items & Drops table at the bottom of this page for
|
||||||
|
more information about special items.<br><br>
|
||||||
|
Maps are the third function in towns. Buying a map to a town places the town in your Travel To box in the left status panel. Once
|
||||||
|
you've purchased a town's map, you can click its name from your Travel To box and you will jump to that town. Travelling this way
|
||||||
|
costs travel points, though, and you'll only be able to visit towns if you have enough travel points.<br><br>
|
||||||
|
The final function in towns is displaying game information and statistics. This includes the latest news post made by the game
|
||||||
|
administrator, a list of players who have been online recently, and the Babble Box.<br><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="exploring"></a>Exploring & Fighting</h3>
|
||||||
|
Once you're done in town, you are free to start exploring the world. Use the compass buttons on the left status panel to move around.
|
||||||
|
The game world is basically a big square, divided into four quadrants. Each quadrant is {control.WorldSize} spaces
|
||||||
|
square. The first town is usually located at (0N,0E). Click the North button from the first town, and now you'll be at (1N,0E).
|
||||||
|
Likewise, if you now click the West button, you'll be at (1N,1W). Monster levels increase with every 5 spaces you move outward
|
||||||
|
from (0N,0E).<br><br>
|
||||||
|
While you're exploring, you will occasionally run into monsters. As in pretty much any other RPG game, you and the monster take turns
|
||||||
|
hitting each other in an attempt to reduce each other's hit points to zero. Once you run into a monster, the Exploring screen changes
|
||||||
|
to the Fighting screen.<br><br>
|
||||||
|
When a fight begins, you'll see the monster's name and hit points, and the game will ask you for your first command. You then get to
|
||||||
|
pick whether you want to fight, use a spell, or run away. Note, though, that sometimes the monster has the chance to hit you
|
||||||
|
first.<br><br>
|
||||||
|
The Fight button is pretty straightforward: you attack the monster, and the amount of damage dealt is based on your attack power and
|
||||||
|
the monster's armor. On top of that, there are two other things that can happen: an Excellent Hit, which doubles your total attack
|
||||||
|
damage; and a monster dodge, which results in you doing no damage to the monster.<br><br>
|
||||||
|
The Spell button allows you to pick an available spell and cast it. See the Spells list at the bottom of this page for more information
|
||||||
|
about spells.<br><br>
|
||||||
|
Finally, there is the Run button, which lets you run away from a fight if the monster is too powerful. Be warned, though: it is
|
||||||
|
possible for the monster to block you from running and attack you. So if your hit points are low, you may fare better by staying
|
||||||
|
around monsters that you know can't do much damage to you.<br><br>
|
||||||
|
Once you've had your turn, the monster also gets his turn. It is also possible for you to dodge the monster's attack and take no
|
||||||
|
damage.<br><br>
|
||||||
|
The end result of a fight is either you or the monster being knocked down to zero hit points. If you win, the monster dies and will
|
||||||
|
give you a certain amount of experience and gold. There is also a chance that the monster will drop an item, which you can put into
|
||||||
|
one of the three inventory slots to give you extra points in your character profile. If you lose and die, half of your gold is taken
|
||||||
|
away - however, you are given back a few hit points to help you make it back to town (for example, if you don't have enough gold to
|
||||||
|
pay for an Inn, and need to kill a couple low-level monsters to get the money).<br><br>
|
||||||
|
When the fight is over, you can continue exploring until you find another monster to beat into submission.<br><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="status"></a>Status Panels</h3>
|
||||||
|
There are two status panels on the game screen: left and right.<br><br>
|
||||||
|
The left panel inclues your current location and play status (In Town, Exploring, Fighting), compass buttons for movement, and the
|
||||||
|
Travel To list for jumping between towns. At the bottom of the left panel is also a list of game functions.<br><br>
|
||||||
|
The right panel displays some character statistics, your inventory, and quick spells.<br><br>
|
||||||
|
The Character section shows the most important character statistics. It also displays the status bars for your current hit points,
|
||||||
|
magic points and travel points. These status bars are colored either green, yellow or red depending on your current amount of each
|
||||||
|
stat. There is also a link to pop up your list of extended statistics, which shows more detailed character information.<br><br>
|
||||||
|
The Fast Spells section lists any Heal spells you've learned. You may use these links any time you are in town or exploring to cast
|
||||||
|
the heal spell. These may not be used during fights, however - you have to use the Spells box on the fight screen for that.
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="items"></a>Items & Drops</h3>
|
||||||
|
<a href="help.php?page=items">Click here</a> for the Items & Drops spoiler page.<br><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="monsters"></a>Monsters</h3>
|
||||||
|
<a href="help.php?page=monsters">Click here</a> for the Monsters spoiler page.<br><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="spells"></a>Spells</h3>
|
||||||
|
<a href="help.php?page=spells">Click here</a> for the Spells spoiler page.<br><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a name="credits"></a>Credits</h3>
|
||||||
|
<ul>
|
||||||
|
<li><b>All program code and stock graphics for the game were created by Jamin Seven</b>.<br><br></li>
|
||||||
|
<li>Major props go to a few people on the PHP manual site, for help with various chunks of code. The specific people are listed in the source code.<br><br></li>
|
||||||
|
<li>Super monkey love goes to Enix and the developers of <i>Dragon Warrior</i>. If it weren't for you guys, my game never would have been made.<br><br></li>
|
||||||
|
<li>Mega props go to Dalez from GameFAQs for his DW3 experience chart, which was where I got my experience levels from.<br><br></li>
|
||||||
|
<li>
|
||||||
|
Mad crazy ninja love goes to the following people for help and support throughout the development process:<br><br>
|
||||||
|
<b>Ideas:</b> (whether they got used or not)
|
||||||
|
<ul>
|
||||||
|
<li>kushet</li>
|
||||||
|
<li>lghtning</li>
|
||||||
|
<li>Ebolamonkey3000</li>
|
||||||
|
<li>Crimson Scythe</li>
|
||||||
|
<li>SilDeath</li>
|
||||||
|
</ul>
|
||||||
|
<b>Beta Testing:</b> (forums name if applicable, character name otherwise)
|
||||||
|
<ul>
|
||||||
|
<li>Ebolamonkey3000</li>
|
||||||
|
<li>lisi</li>
|
||||||
|
<li>Junglist</li>
|
||||||
|
<li>Crimson Scythe</li>
|
||||||
|
<li>Sk8erpunk69</li>
|
||||||
|
<li>lghtning</li>
|
||||||
|
<li>kushet</li>
|
||||||
|
<li>SilDeath</li>
|
||||||
|
<li>lowrider4life</li>
|
||||||
|
<li>dubiin</li>
|
||||||
|
<li>Sam Wise The Great</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
Apologies and lots of happy naked love to anyone I forgot. <br><br>
|
||||||
|
And of course, thanks to <b>you</b> for playing my game! <br><br>
|
||||||
|
<a href="/index.php?do=ninja">NINJA!</a> <br><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
Please visit the following sites for more information:<br>
|
||||||
|
<a href="http://www.se7enet.com" target="_new">Se7enet</a> (Jamin's homepage)<br>
|
||||||
|
<a href="http://dragon.se7enet.com/dev.php" target="_new">Dragon Knight</a> (official DK homepage)<br>
|
||||||
|
<a href="http://se7enet.com/forums" target="_new">Forums</a> (official DK forums)<br><br>
|
||||||
|
All original coding and graphics for the <i>Dragon Knight</i> game engine are © 2003-2005 by Jamin Seven.<br><br>
|
||||||
|
[ <a href="#top">Top</a> ]
|
||||||
|
{/block}
|
Loading…
x
Reference in New Issue
Block a user