HowToAddMapsServerStendhal: Difference between revisions

Jump to navigation Jump to search
Content deleted Content added
imported>Kymara
Create a map file: more corrections.
imported>Hendrik Brummermann
 
(76 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Navigation for Stendhal Top|Extending}}
{{Navigation for Stendhal Extenders}}
Of course you have already read:
Of course you have already read:
* [[HowToUseTiledToCreateStendhalMaps]]
* [[HowToUseTiledToCreateStendhalMaps]]
Line 9: Line 11:
= Modify world.tmx=
= Modify world.tmx=
Now make sure if your map is new that world.tmx shows it by adding a new tileset with your map image.
Now make sure if your map is new that world.tmx shows it by adding a new tileset with your map image.
This step is just for your mental wellness. Stendhal don't use world.tmx.
This step is just for your mental wellness. Stendhal doesn't use world.tmx.


= Create a map file=
= Create a map file=
Line 29: Line 31:


<pre>
<pre>
<zone-group uri="zones/<area>.xml"/>
<group uri="zones/<area>.xml"/>
</pre>
</pre>


To enable a zone in the server, edit the file '''data/conf/zones/<area>.xml''' and add an entry (in the appropriate level/top-down/left-right order), giving it the zone name and map tmx file to use:
To enable a zone in the server, edit the file '''data/conf/zones/<area>.xml''' and add an entry (in the appropriate level/top-down/left-right order), giving it the zone name and map tmx file to use:


<source lang="xml">
<pre>
<zone name="int_myarea_mylocation" file="interiors/myarea/mylocation.tmx"/>
<zone name="int_myarea_mylocation" file="interiors/myarea/mylocation.tmx"/>
<zone name="0_myarea_mylocation" level="0" x="100000" y="200000" file="Level 0/myarea/mylocation.tmx">
<zone name="0_myarea_mylocation" level="0" x="100000" y="200000" file="Level 0/myarea/mylocation.tmx"/>
</pre>
</source>


In the case of non-interior zones, the level and x/y coordinate should also be included in the <zone> element (setting them in the tmx file has been deprecated). For interior zones, the level xml attribute should '''not''' be set (for now). The coordinate starts at the top-left corner, and should align against (but never overlap) other zones in the same level.
In the case of non-interior zones, the level and x/y coordinate should also be included in the <zone> element (setting them in the tmx file has been deprecated). For interior zones, the level xml attribute should '''not''' be set (for now). The coordinate starts at the top-left corner, and should align against (but never overlap) other zones in the same level.

If the new zone is outside, or otherwise should follow the normal daylight cycle, add a coloring method definition to it, like this:

<source lang="xml">
<zone name="0_myarea_mylocation" level="0" x="100000" y="200000" file="Level 0/myarea/mylocation.tmx">
<attributes>
<parameter name="color_method">time</parameter>
</attributes>
</zone>
</source>

About other possible coloring methods for maps, see [[LightsAndColor | Lights and Color]].


Most zones can be configured just using this xml file. However, there are currently some things, such as NPC's that need special handling. If you need to do custom zone configuration, create one or more new java source file(s) at '''src/games/stendhal/server/maps/<area>/<base-location>/<entity>.java'''. The '''<area>/<base-location>''' path would essentially be the same as your '''.tmx''' file uses. In case where locations have been split due to size (like _nw, _ne, _s, _n, etc), only the base location name is used.
Most zones can be configured just using this xml file. However, there are currently some things, such as NPC's that need special handling. If you need to do custom zone configuration, create one or more new java source file(s) at '''src/games/stendhal/server/maps/<area>/<base-location>/<entity>.java'''. The '''<area>/<base-location>''' path would essentially be the same as your '''.tmx''' file uses. In case where locations have been split due to size (like _nw, _ne, _s, _n, etc), only the base location name is used.
Line 57: Line 71:
Open the file and make sure that it looks like this:
Open the file and make sure that it looks like this:


<source lang="java">
<pre>
package games.stendhal.server.maps.myarea.mylocation;
package games.stendhal.server.maps.myarea.mylocation;


Line 64: Line 78:
import games.stendhal.server.config.ZoneConfigurator;
import games.stendhal.server.config.ZoneConfigurator;


public class MyEntity implements ZoneConfigurator
public class MyEntity implements ZoneConfigurator {
/**
{
/**
* Configure a zone.
* Configure a zone.
*
* @param zone The zone to be configured.
*
* @param zone The zone to be configured.
* @param attributes Configuration attributes.
*/
* @param attributes Configuration attributes.
public void configureZone(StendhalRPZone zone, Map<String, String> attributes) {
*/
// Add/configure entity to "zone", using optional configuration "attributes"
public void configureZone(StendhalRPZone zone, Map<String, String> attributes) {
}
// Add/configure entity to "zone", using optional configuration "attributes"
}
}
}
</pre>
</source>


For each custom configuration code class, add appropriate "<configurator>" entries in your "<zone>" element, using the fully qualified package/class name of your java classes:
For each custom configuration code class, add appropriate "<configurator>" entries in your "<zone>" element, using the fully qualified package/class name of your java classes:


<source lang="xml">
<pre>
<zone name="int_myarea_mylocation" file="interiors/myarea/mylocation.tmx">
<zone name="int_myarea_mylocation" file="interiors/myarea/mylocation.tmx">
<configurator class-name="games.stendhal.server.maps.myarea.mylocation.MyEntity"/>
<configurator class-name="games.stendhal.server.maps.myarea.mylocation.MyEntity"/>
</zone>
</zone>
</pre>
</source>


Now once it is added, test the result by starting server.
Now once it is added, test the result by starting server.
Line 99: Line 112:


There are several types of portals:
There are several types of portals:
* Portal
* Portal ''added using xml''
* One way portal
* One way portal ''added using xml''
* Stairs portals
* Stairs portals ''added using tiled''
* House Door portals.
* House Door portals ''added using tiled''


A portal is just the generic portal. It works for almost everything you can imagine.
A portal is just the generic portal. It works for almost everything you can imagine.


Portals are created by adding a entries to your zone in '''zones.xml'''. For example creating a portal to an internal building entrance which is at 1 12 inside the building (and the outer entrance to go in is at 10 15) might look like:
Portals are created by adding a entries to your zone in '''zones.xml'''. For example creating a portal to an internal building entrance which is at 1 12 inside the building (and the outer entrance to go in is at 10 15) might look like:


<source lang="xml">
<pre>
<zone name="int_myarea_mylocation" file="interiors/myarea/mylocation.tmx">
<zone name="int_myarea_mylocation" file="interiors/myarea/mylocation.tmx">
<portal x="1" y="12" ref="entrance">
<portal x="1" y="12" ref="entrance">
Line 120: Line 133:
</portal>
</portal>
</zone>
</zone>
</pre>
</source>


The '''ref''' attribute of a portal should be a name unique to the zone it is in (and meaningful). This value has a corresponding reference via the '''<destination>''' ref name. You are responsible for correctly assigning the ref names of each portal.
The '''ref''' attribute of a portal should be a name unique to the zone it is in (and meaningful). This value has a corresponding reference via the '''<destination>''' ref name. You are responsible for correctly assigning the ref names of each portal.
Line 126: Line 139:
A one way portal is a portal that only exists as endpoint, so none can use the portal to move back to the origin. For one way portals, there is no '''<destination>''' sub-element, as they don't go anywhere. Also, you need to provide a non-default implementation:
A one way portal is a portal that only exists as endpoint, so none can use the portal to move back to the origin. For one way portals, there is no '''<destination>''' sub-element, as they don't go anywhere. Also, you need to provide a non-default implementation:


<source lang="xml">
<pre>
<portal x="11" y="44" ref="my_exit">
<portal x="11" y="44" ref="my_exit">
<implementation class-name="games.stendhal.server.entity.portal.OneWayPortalDestination"/>
<implementation class-name="games.stendhal.server.entity.mapstuff.portal.OneWayPortalDestination"/>
</portal>
</portal>
</pre>
</source>

The House door portal is a special type of portal that automatically creates all the portals and areas needed to add a house to that zone with its entrance on point where the portal is.

Finally the stairs portals also automate the creation of stairs between two areas. It is very important that the portals ( both ends ) are exactly on the same position but on different levels. Position means absolute position. Also, due to current implementation, be careful '''not''' to place omni-directional stair portals at the same exact location between adjacent levels if they're not meant to be linked, as they might inadvertantly be linked. Directional stairs are safer and only link with the level they go toward.

== Adding NPCs ==
Usually we add NPCs (non-player characters) to make world more alive and to use them in Quests. It is because of that reason, that is so important that you add NPC on the zone they are.

=== The old way ===

This is how NPCs used to be added to the world. The downside of this is that you need a lot of Java code. If you're adding new NPCs, consider using the new way of doing it, as described in the next section.

''SpeakerNPC npc = new SpeakerNPC() { ... }'' creates a new NPC. When added to a zone, NPCs are added it to a global list so next time you need to get the NPC for participating in a quest, or if you want to teleportto it, you can call it by its ''name'' using ''NPCList.get().get(name)''.
<pre>
SpeakerNPC npc = new SpeakerNPC("name") {
/...
});
</pre>

An example is:

<pre>
SpeakerNPC npc = new SpeakerNPC("Ilisa") {
protected void createPath() {
List<Node> nodes=new LinkedList<Node>();
nodes.add(new Path.Node(9,5));
nodes.add(new Path.Node(14,5));
setPath(nodes,true);
}

protected void createDialog() {
// Lets the NPC reply with "Hallo" when a player greets her
addGreeting();
// Lets the NPC reply when a player says "job"
addJob("I have healing abilities and I heal wounded players. I also sell potions and antidotes.");
// Lets the NPC reply when a player asks for help
addHelp("Ask me to #heal you and I will help you or ask me #offer and I will show my shop's stuff.");
// Makes the NPC sell potions and antidote
addSeller(new SellerBehaviour(shops.get("healing")));
// Lets the NPC heal players for free
addHealer(0);
addGoodbye();
}
});

zone.assignRPObjectID(npc);
// This determines how the NPC will look like.
npc.setEntityClass("welcomernpc");
npc.setPotition(9, 5);
npc.initHP(100);

zone.add(npc);
</pre>

Because the NPC is added to a list of NPC from where you can later obtain it for adding more dialogues for quests. Make sure the name you give to your NPC is unique.

Just after that it is a good idea to create a path that the NPC will follow on that area.
And then create a dialog. Dialogs and such are explained in Quest sections.

Now simply assign an id to the NPC, set its outfit either by:
* setting its class to a PNG image that exists at ''data/sprites/npc''
* setting its outfit with setOutfit method.
See [[StendhalOpenTasks#Player's outfits| How to know player's outfits specifications]]

Finally set its initial position and its HP. Don't worry for your NPC. It can't be attacked nor killed.

Once that is done add the NPC to zone using ''zone.add()'' method.

=== The new way ===
'''Don't use this. Use the all java way above. This way you have to edit two files to keep track of your NPC! We don't want that.'''
This is the new way of adding NPCs. It requires less Java coding skills; Java code is only required for the dialog and for special behaviour, everything else is defined in XML.

First, you need to create a Java file for the dialog. You should put it in a subpackage of <code>games.stendhal.server.maps</code>; the package describes where NPC is located.

For example, here is the Java code for a simple NPC on Athor island:

package games.stendhal.server.maps.athor.holiday_area;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.SpeakerNPCFactory;
public class SwimmerNPC extends SpeakerNPCFactory {
@Override
protected void createDialog(SpeakerNPC npc) {
npc.addGreeting("Don't disturb me, I'm trying to establish a record!");
npc.addQuest("I don't have a task for you, I'm too busy.");
npc.addJob("I am a swimmer!");
npc.addHelp("Try the diving board! It's fun!");
npc.addGoodbye("Bye!");
};
}


The House door portal is a special type of portal that automatically creates all the portals and areas needed to add a house to that zone with its entrance on point where the portal is. In tiled/tileset/logic/portals.png it's the one with the door on it. Add it to the 'city' type map where you want the house entrance. Please see [[HowToUseTiledToCreateStendhalMaps2#Objects_revisited|the tiled tutorial]].
This will make the NPC react to typical words that players might say to him, e.g. "hi", "help", and "bye". This Java class is stored in the file <code>/src/games/stendhal/server/maps/athor/holiday_area/SwimmerNPC.java</code>. Of course this is just a simple example, and more sophisticated dialogs and behaviours are possible with more complex Java code.


Finally the stairs portals also automate the creation of stairs between two areas. It is very important that the portals ( both ends ) are exactly on the same position but on different levels. Position means absolute position. Also, due to current implementation, be careful '''not''' to place omni-directional stair portals at the same exact location between adjacent levels if they're not meant to be linked, as they might inadvertantly be linked. Directional stairs are safer and only link with the level they go toward. The [[HowToUseTiledToCreateStendhalMaps2#Objects_revisited|the tiled tutorial]] covers this in more detail.
Next, we need place the NPC and set the name and some other attributes. The NPC in the example lives on Athor island, so the information is stored in <code>data/conf/zones/athor.xml</code>. The map he's on is called 0_athor_island, so the information is inside the <code><zone name="0_athor_island"...> ... </zone></code> tag:


=== Condition and Action Portals ===
<entity x="67" y="63">
Portals are being refactored to allow combinations of conditions and actions in a very similar way to NPCs. In fact, you can use the same conditions and actions.
<implementation class-name="games.stendhal.server.maps.athor.holiday_area.SwimmerNPC">
The full list is found in http://arianne.cvs.sourceforge.net/arianne/stendhal/src/games/stendhal/server/entity/npc/action and http://arianne.cvs.sourceforge.net/arianne/stendhal/src/games/stendhal/server/entity/npc/condition
<parameter name="name">Enrique</parameter>
<parameter name="node0">67,68</parameter>
<parameter name="node1">67,63</parameter>
</implementation>
<attribute name="class">swimmer3npc</attribute>
</entity>


A portal which you can put a Condition and / or action to is called a ConditionAndActionPortal. You don't have to set both a condition and an action.
* The first line says that the NPC should initially be placed at the point (67, 63).
* The second line tells the server where we stored our Java file with the dialog.
* The third line says that our NPC should be called Enrique.
* The fourth and fifth lines define the path along which Enrique should walk/swim. He will first visit the point (67, 68), then return to his start position (67, 63), and continue like this infinitely. You can of course create NPCs with more than 2 nodes, but:
** keep in mind that counting starts with 0
** make sure that you don't forget a node number, e.g. if you have node6, you must also have node5, node4 etc.


Implement them like this:
* The 'class' attribute defines how the NPC should look like. In this case, the graphics from the file <code>data/sprites/npc/swimmer3npc.png</code> will be used.


<source lang="xml">
If you don't want your NPC to walk around, just leave out the node parameters. Instead, you should add a parameter that defines in which direction the NPC should look on server startup (left, right, up, down), e.g.:
<portal x="64" y="117" ref="entrance">
<destination zone="-1_semos_chasm_n" ref="exit" />
<implementation class-name="games.stendhal.server.entity.mapstuff.portal.ConditionAndActionPortal">
<parameter name="condition">new PlayerHasItemWithHimCondition("special magical thingy", 10)</parameter>
<parameter name="action">new DropItemAction("special magical thingy", 10)</parameter>
<parameter name="rejected">You need 10 of the special magical thingies.</parameter>
</implementation>
</portal>
</source>


You can use NotConditions:
<parameter name="direction">down</parameter>


<source lang="xml">
Other attributes you can use:
<portal x="65" y="13" ref="entrance">
<destination zone="-1_semos_chasm_w" ref="exit" />
<implementation class-name="games.stendhal.server.entity.mapstuff.portal.ConditionAndActionPortal">
<parameter name="condition">new NotCondition(new PlayerHasPetOrSheepCondition())</parameter>
<parameter name="rejected">To get into the evil chasm you must bring a sacrificial animal</parameter>
</implementation>
</portal>
</source>


You can do more than one action by using MultipleActions and list the actions for it, and combine Conditions with an AndCondition, listing the conditions for it.
<attribute name="hp">50</attribute>
The syntax is slightly different than with NPCs, please note these extra [ ] surrounding the list. This is due to a bug in groovy.


<source lang="xml">
This will make the NPC look wounded (the health bar will be at the middle). Note that, as NPCs cannot be killed, this is only for decoration. If you leave this parameter out, the hitpoints will be set to 100, which means full health.
<portal x="37" y="16" ref="example1">
<destination zone="int_semos_zone" ref="choice_floor_1" />
<implementation class-name="games.stendhal.server.entity.mapstuff.portal.ConditionAndActionPortal">
<parameter name="condition">new AndCondition([new NotCondition(new PlayerHasItemWithHimCondition("claymore")) , new LevelLessThanCondition(100)])</parameter>
<parameter name="action">new MultipleActions([new IncreaseXPAction(100), new EquipItemAction("claymore")])</parameter>
</implementation>
</portal>
</source>


The destination settings and references are all as normal. You can still set other attributes like a reject message and hidden from minimap, as in some of the examples above.
<attribute name="level">10</attribute>


== Adding NPCs==
This sets the NPC's level of experience. Again, this is only for decoration, as NPCs don't fight or die.
See [[Stendhal NPC Coding]]