Implementing Multiple Areas (PHP)

Now that we’ve prepared our database for multiple areas, it’s time to build multiple area support into our exploration/combat system.

To begin with, check out version 46 from the Google Code Project:

svn checkout http://building-browsergames-tutorial.googlecode.com/svn/trunk/php/pbbg tutorial -r 46

With that done, we can get down to business. Start by copying all of forest.php’s code over to explore.php, which is going to be the new location of our exploration code. Once that’s done, we need to change the way that our script retrieves the current monster for a player to fight:

129
130
131
132
133
134
135
136
137
138
$area_id = $_GET['area'];
$query = sprintf("SELECT monster FROM area_monsters WHERE area = %s ORDER BY RAND() LIMIT 1",
    mysql_real_escape_string($area_id));
$result = mysql_query($query);
list($monster_id) = mysql_fetch_row($result);
$query = sprintf("SELECT name FROM monsters WHERE id = %s",
    mysql_real_escape_string($monster_id));
$result = mysql_query($query);
list($monster) = mysql_fetch_row($result);
$smarty->assign('monster',$monster);

Note: this code should overwrite your old code, starting at line 129. We are modifying the way that monster retrieval works.

With the code changes made, we should set up areas and monsters in areas for our code to retrieve:

INSERT INTO areas(name) VALUES ('Forest');
INSERT INTO areas(name) VALUES ('Woods');
INSERT INTO area_monsters(area,monster) VALUES (1,1);
INSERT INTO area_monsters(area,monster) VALUES (1,2);
INSERT INTO area_monsters(area,monster) VALUES (2,3);

With the new data inserted, try visiting explore.php?area=1, and see what happens – you should only ever see monsters that belong in the area with the ID of 1.

While you’re testing, you might notice that the title tag of our page still says ‘The Forest’ – while we’re at it, we may as well modify our code to also retrieve the name of the area we are currently visiting:

140
141
142
143
144
145
146
147
$query = sprintf("SELECT name FROM areas WHERE id = %s",
    mysql_real_escape_string($_GET['area']));
$result = mysql_query($query);
list($area_name) = mysql_fetch_row($result);
$smarty->assign('area',$area_name);
$smarty->assign('area_id',$_GET['area']);
 
$smarty->display('explore.tpl');

That code should be outside any of the code responding to whether our page is being POST’d to or not; we need to set the page title properly whether we’re just encountering something, or completing a fight. You’ll notice that we have also set the area_id – this is because we will need to tweak where the form in our template goes, in addition to renaming it from forest.tpl to explore.tpl:

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	<title>The {$area}</title>
</head>
<body>
	{if $combat eq ''}
		<p>You've encountered a {$monster}!</p>
		<form action='explore.php?area={$area_id}' method='post'>
			<input type='submit' name='action' value='Attack' /> or 
			<input type='submit' name='action' value='Run Away' />
			<input type='hidden' name='monster' value='{$monster}' />
		</form>
	{else}
		<ul>
		{foreach from=$combat key=id item=i}
			<li><strong>{$i.attacker}</strong> attacks {$i.defender} for {$i.damage} damage!</li>
		{/foreach}
		</ul>
		{if $won eq 1}
			<p>You killed <strong>{$smarty.post.monster}</strong>! You gained <strong>{$gold}</strong> gold, and {$exp} experience.</p>
			{if $level_up eq 1}
			    <p><strong>You gained a level!</strong></p>
			{/if}
			<p>You found a <strong>{$item}</strong>!</p>
			<p><a href='explore.php?area={$area_id}'>Explore Again</a></p>

With those changes made, we’re finished! Your game can now support multiple different areas where players can encounter enemies – just link them to explore.php?area=1 for area 1, explore.php?area=2 for area 2, and so on. Here’s what our new code files look like:

explore.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
 
require_once 'smarty.php';
require_once 'weapon-stats.php';
require_once 'login-check.php';
 
session_start();
 
require_once 'config.php';		// our database settings
$conn = mysql_connect($dbhost,$dbuser,$dbpass)
	or die('Error connecting to mysql');
mysql_select_db($dbname);
 
if($_POST) {
	if($_POST['action'] == 'Attack') {
		require_once 'stats.php';			// player stats
		require_once 'monster-stats.php';	// monster stats
		// to begin with, we'll retrieve our player and our monster stats 
		$query = sprintf("SELECT id FROM users WHERE UPPER(username) = UPPER('%s')",
					mysql_real_escape_string($_SESSION['username']));
		$result = mysql_query($query);
		list($userID) = mysql_fetch_row($result);
		$player = array (
			name		=>	$_SESSION['username'],
			attack 		=>	getStat('atk',$userID),
			defence		=>	getStat('def',$userID),
			curhp		=>	getStat('curhp',$userID)
		);
		$phand = getStat('phand',$userID);
		$atk = getWeaponStat('atk',$phand);
		$player['attack'] += $atk;
		require_once 'armor-stats.php';		// armor stats
		$armor = array('atorso','ahead','alegs','aright','aleft');
		foreach ($armor as $key) {
			$id = getStat($key,$userID);
			$defence = getArmorStat('defence',$id);
			$player['defence'] += $defence;
		}		
 
		$query = sprintf("SELECT id FROM monsters WHERE name = '%s'",
					mysql_real_escape_string($_POST['monster']));
		$result = mysql_query($query);
		list($monsterID) = mysql_fetch_row($result);
		$monster = array (
			name		=>	$_POST['monster'],
			attack		=>	getMonsterStat('atk',$monsterID),
			defence		=>	getMonsterStat('def',$monsterID),
			curhp		=>	getMonsterStat('maxhp',$monsterID)
		);
		$combat = array();
		$turns = 0;		
		while($player['curhp'] > 0 && $monster['curhp'] > 0 && $turns <= 100) {
			if($turns % 2 != 0) {
				$attacker = &$monster;
				$defender = &$player;	
			} else {
				$attacker = &$player;
				$defender = &$monster;
			}
			$damage = 0;
			if($attacker['attack'] > $defender['defence']) {
				$damage = $attacker['attack'] - $defender['defence'];	
			}
			$defender['curhp'] -= $damage;
			$combat[$turns] = array(
				attacker	=>	$attacker['name'],
				defender	=>	$defender['name'],
				damage		=>	$damage
			);
			$turns++;
		}
		setStat('curhp',$userID,$player['curhp']);
		if($player['curhp'] > 0) {
			// player won
			setStat('gc',$userID,getStat('gc',$userID)+getMonsterStat('gc',$monsterID));	
			$smarty->assign('won',1);
			$smarty->assign('gold',getMonsterStat('gc',$monsterID));
			$rand = rand(0,100);
			$query = sprintf("SELECT item_id FROM monster_items WHERE monster_id = %s AND rarity >= %s ORDER BY RAND() LIMIT 1",
				mysql_real_escape_string($monsterID),
				mysql_real_escape_string($rand));
			$result = mysql_query($query);
			list($itemID) = mysql_fetch_row($result);
			$query = sprintf("SELECT count(id) FROM user_items WHERE user_id = '%s' AND item_id = '%s'",
				mysql_real_escape_string($userID),mysql_real_escape_string($itemID));
			$result = mysql_query($query);
			list($count) = mysql_fetch_row($result);
			if ($count > 0) {
				# already has one of the item
				$query = sprintf("UPDATE user_items SET quantity = quantity + 1 WHERE user_id = '%s' AND item_id = '%s'",
					mysql_real_escape_string($userID),
					mysql_real_escape_string($itemID));
			} else {
				# has none - new row
				$query = sprintf("INSERT INTO user_items(quantity,user_id,item_id) VALUES (1,'%s','%s')",
					mysql_real_escape_string($userID),
					mysql_real_escape_string($itemID));
			}
			mysql_query($query);
			# retrieve the item name, so that we can display it
			$query = sprintf("SELECT name FROM items WHERE id = %s",
				mysql_real_escape_string($itemID));
			$result = mysql_query($query);
			list($itemName) = mysql_fetch_row($result);
			$smarty->assign('item',$itemName);
 
			$monster_exp = getMonsterStat('exp',$monsterID);
			$smarty->assign('exp',$monster_exp);
			$exp_rem = getStat('exp_rem',$userID);
			$exp_rem -= $monster_exp;
			$level_up = 0;
			if($exp_rem <= 0) {
			    // level up!
			    $exp_rem = 100;
			    $level_up = 1;
			}
		    $smarty->assign('level_up',$level_up);
			setStat('exp_rem',$userID,$exp_rem);
		} else {
			// monster won
			$smarty->assign('lost',1);	
		}
		$smarty->assign('combat',$combat);
	} else {
		// Running away! Send them back to the main page
		header('Location: index.php');	
	}
} else {
    $area_id = $_GET['area'];
    $query = sprintf("SELECT monster FROM area_monsters WHERE area = %s ORDER BY RAND() LIMIT 1",
        mysql_real_escape_string($area_id));
    $result = mysql_query($query);
    list($monster_id) = mysql_fetch_row($result);
    $query = sprintf("SELECT name FROM monsters WHERE id = %s",
        mysql_real_escape_string($monster_id));
    $result = mysql_query($query);
    list($monster) = mysql_fetch_row($result);
    $smarty->assign('monster',$monster);
}
 
$query = sprintf("SELECT name FROM areas WHERE id = %s",
    mysql_real_escape_string($_GET['area']));
$result = mysql_query($query);
list($area_name) = mysql_fetch_row($result);
$smarty->assign('area',$area_name);
$smarty->assign('area_id',$_GET['area']);
 
$smarty->display('explore.tpl');
 
?>

explore.tpl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<html>
<head>
	<title>The {$area}</title>
</head>
<body>
	{if $combat eq ''}
		<p>You've encountered a {$monster}!</p>
		<form action='explore.php?area={$area_id}' method='post'>
			<input type='submit' name='action' value='Attack' /> or 
			<input type='submit' name='action' value='Run Away' />
			<input type='hidden' name='monster' value='{$monster}' />
		</form>
	{else}
		<ul>
		{foreach from=$combat key=id item=i}
			<li><strong>{$i.attacker}</strong> attacks {$i.defender} for {$i.damage} damage!</li>
		{/foreach}
		</ul>
		{if $won eq 1}
			<p>You killed <strong>{$smarty.post.monster}</strong>! You gained <strong>{$gold}</strong> gold, and {$exp} experience.</p>
			{if $level_up eq 1}
			    <p><strong>You gained a level!</strong></p>
			{/if}
			<p>You found a <strong>{$item}</strong>!</p>
			<p><a href='explore.php?area={$area_id}'>Explore Again</a></p>
		{/if}
		{if $lost eq 1}
			<p>You were killed by <strong>{$smarty.post.monster}</strong>.</p>
		{/if}		
			<p><a href='index.php'>Back to main</a></p>
	{/if}
</body>
</html>

Extra Credit

  • Make it so that when the user visits explore.php without passing in an area to visit, a random area is selected for them to explore.

Wish there was more?

I'm considering writing an ebook - click here.

.

Luke is the primary editor of Building Browsergames, and has written a large portion of the articles that you read here. He generally has no idea what to say when asked to write about himself in the third person.

Tags: , , , ,

Thursday, January 15th, 2009 buildingbrowsergames, medieval
  • Great, thanks !
    I read all the tutorials, this is pretty nice work and thanks again for sharing it. Is kinda good for games based on fighting and stuff like that, exploring, items. Will be great to see a tutorial for online businesses, economy or something. That's what people actually want now.

    Cheers!
    Franko Saloma
    Free pornstars pictures && Filme XXX

blog comments powered by Disqus

About

Building Browsergames is a blog about browsergames(also known as PBBG's). It's geared towards the beginner to intermediate developer who has an interest in building their own browsergame.

Sponsors

Got Something to Say?

Send an e-mail to luke@buildingbrowsergames.com, or get in touch through Twitter at http://twitter.com/bbrowsergames