Now I know the basic roundtrip wasn't that exciting yet. It shows how the principle works, but there is of course a lot of work that still has to be done to get anything remotely similar to cRPG going. What we are going to do now is expand on the first part, so that we can make use of the information that is coming from the character server and make available a few items to the player according to the information we get back.
The first thing we have to do is create new troop types that don't have any preset items and attributes/skills, because we are going to assign those with information taken from the character server. I also recommend to create new factions for this, which is why you should open module_factions.py and search for the text "kingdom_6". As you can see, these 6 lines define the native Warband factions. Paste the following code below them:
("kingdom_7", "Kingdom of Kingliness", 0, 0.9, [], [], 0x1133BB),
("kingdom_8", "Free state of Freedomhood", 0, 0.9, [], [], 0xBB1111),
This defines two new kingdoms. If you want to learn about the individual values, read the topmost part of the file, each field is explained there.
The next part is a bit tedious, because you have to register those new factions in several locations. I recommend to follow this tutorial:
http://forums.taleworlds.com/index.php/topic,116286.msg2801692.html#msg2801692 Come back, once you are done with module_presentations.py and module_scripts.py.
Now that our factions are added, we have to create a troop and assign it to them. Open module_troops.py and search for the text "sarranid_mamluke_multiplayer". This is the entry for the cavalry class of the Sarranids in native (note that it spans multiple lines). We are going to paste the following code directly below this block:
["fighter1","Fighter","Fighters",tf_guarantee_all,0,0,fac_kingdom_7,
[],
def_attrib_multiplayer|level(1),wpe(0,0,0,0),0,swadian_face_young_1,swadian_face_old_2],
["fighter2","Fighter","Fighters",tf_guarantee_all,0,0,fac_kingdom_8,
[],
def_attrib_multiplayer|level(1),wpe(0,0,0,0),0,swadian_face_young_1,swadian_face_old_2],
We are going to add two empty troops, one for each kingdom, because I couldn't figure out how to add the same troop to multiple kingdoms. chadz mentioned that they completely removed native restrictions such as this one, but unfortunately, I don't know how to do that.
Now that our troops are ready, we can get to the more interesting stuff. Open module_scripts.py and search for the text "multiplayer_server_player_joined_common". At the bottom of this block are the lines of code we inserted in the first part. Change them to this:
# dRPG hook
(player_get_unique_id, ":player_unique_id", ":player_no"),
(assign, reg0, ":player_unique_id"),
(assign, reg1, ":player_no"),
(str_store_player_username, s1, ":player_no"),
(server_add_message_to_log, "@http://localhost/dRPG/character.php?id={reg0}&name={s1}&no={reg1}"),
(send_message_to_url, "@http://localhost/dRPG/character.php?id={reg0}&name={s1}&no={reg1}"),
In addition to the player's name and unique id, we are now also sending his ingame player number (starts from 1, increases when someone joins) to the server. You will see why in a moment.
Now to find the location where the server's response is processed, search for the text "game_receive_url_response". Again, the code block contained therein should be familiar, because it's what we added in part 1. Replace it with this:
# dRPG hook
# Response: s0 = player name, reg0 = player number, reg1 = item1, reg2 = item2
(server_add_message_to_log, "@Received response: {s0} {reg0} {reg1} {reg2}"),
(multiplayer_send_4_int_to_player, reg0, 113, reg1, reg2, 0, 0),
(call_script, "script_multiplayer_set_item_available_for_troop", reg1, "trp_fighter1"),
(call_script, "script_multiplayer_set_item_available_for_troop", reg2, "trp_fighter1"),
(call_script, "script_multiplayer_set_item_available_for_troop", reg1, "trp_fighter2"),
(call_script, "script_multiplayer_set_item_available_for_troop", reg2, "trp_fighter2"),
Now, it's important to understand that this code block is only run on the game server, since he is the only machine that gets the response from the character server. This means we'll have to send the values from the character server's response to the correct client machine, which is done with the multiplayer_send_bla command. This command needs a player number to know which machine to send the information to, which is why we added the player number to the character server roundtrip. It will sit in reg0, and can be used as destination in the multiplayer_send_bla command. We also hardcode a new event type here (113), for which we are going to filter later on. And the rest of the command are the retrieved values (only two for the moment, for the remaining two, we send 0).
After that, we finally set the items received from the server as available for our new troop types (but only on the server so far).
Now search for the text "cf_multiplayer_evaluate_poll". We are not going to edit this block, but the one above it, which is a long ass block, so you are faster if you go to the block below, because we are again going to add to the end of it, right after "(display_message, "str_server_s0", 0xFFFF6666)," and before "(try_end),":
# dRPG hook
(else_try),
(eq, ":event_type", 113),
(store_script_param, ":item1", 3),
(store_script_param, ":item2", 4),
(store_script_param, ":item3", 5),
(store_script_param, ":item4", 6),
(display_message, "@Client received server call"),
(call_script, "script_multiplayer_set_item_available_for_troop", ":item1", "trp_fighter1"),
(call_script, "script_multiplayer_set_item_available_for_troop", ":item2", "trp_fighter1"),
(call_script, "script_multiplayer_set_item_available_for_troop", ":item1", "trp_fighter2"),
(call_script, "script_multiplayer_set_item_available_for_troop", ":item2", "trp_fighter2"),
In this block, we are first checking whether it's our event type 113 that has been sent. If yes, we store the sent values in easy to access variables, display a message, and then assign the items to our troops like we did on the server.
That's it for the module, compile it and when it's done, copy it to the dedicated server.
The last thing we now have to do is change the code on the character server. Open your character.php file and change the code to this:
<?php
$id = $_GET['id'];
$name = $_GET['name'];
$no = $_GET['no'];
echo "$name|$no|434|437";
?>
We retrieve the unique id (not used atm), player name and player number from the request and send back a hardcoded message with player name, player number and two items. These items are the "Sword" (itm_sword_medieval_a) and "Arming Sword" (itm_sword_medieval_c). I tried different items, but it seems that there are further restrictions in place that will have to be overcome at a later date, because not all worked. You can also see that they are hardcoded as number. The numbers are their id in the item_kinds1.txt. It's unfortunately not possible to work with item identifiers at runtime, I guess because the module systems compiles them into the integer numbers as we use them above.
To make sure the dedicated server uses our new factions only, edit the "Sample_Battle.txt" file and find the text "add_factions" replace the whole block up until and including the line "set_randomize_factions 1" with the following:
add_factions fac_kingdom_7 fac_kingdom_8
#add_factions fac_kingdom_2 fac_kingdom_2
#add_factions fac_kingdom_3 fac_kingdom_3
#add_factions fac_kingdom_4 fac_kingdom_4
#add_factions fac_kingdom_5 fac_kingdom_5
#add_factions fac_kingdom_6 fac_kingdom_6
#set_randomize_factions 1
This adds our first new kingdom as faction one and the second new kingdom as faction two and disables randomization.
That's it for part 2. Make sure Apache is started in your xampp control panel, launch the dedicated server, launch warband with your module and connect to the server. You should see the message "Client received server call" after about a second and be able to choose one of our new factions and the troop "Fighter". This troop should have the "Sword" and "Arming Sword" as weapons, once you click any of the righthand empty hand symbols (weapon slots).
The next step will be to assign stats to the player. You will be able to read about it here in part 3, once I get my lazy ass up and dig into the matter.