Log in

Coding Cards in C Tutorial

Before you start coding new cards, make sure you know the basics of how to add non-coded cards. This can all be found in the basic tutorial, level 0.

If nothing else is stated below, it is assumed that your Magic game is installed in C:\magic. If that is not the case, just replace C:\magic with whichever directory you used.


Contents

Getting Started

The hardest part about coding cards in C may be getting started! These are the steps I followed to get up and running. Several of them may be unnecessary, but it's the only way I know. (I did this in Win XP)

  1. Download and install Camelbox (http://www.softpedia.com/progDownload/CamelBox-Download-105269.html)
  2. Choose to install all of the components offered, and make sure camelbox/bin is added to your path.
  3. Download the latest copy of the manalink distribution.
  4. Unzip the distribution into c:\magic
  5. Delete everything from c:\camelbox\bin\cards and c:\camelbox\bin\functions, if they exist.
  6. Copy everything from c:\magic\src into c:\camelbox\bin (you should now have c:\camelbox\bin\build.pl and c:\camelbox\bin\cards). Also, see note below.
  7. Make sure that the build.pl file uses the correct path to your Magic game. To do this, first open c:\camelbox\bin\build.pl and locate the following function:
    "copy('ManalinkEh.dll', PATH)" where PATH looks something like this: 'e:\magic\ManalinkEh.dll'. Now change PATH so that it targets the ManalinkEh.dll file in your Magic directory. Save the edits.
  8. Make sure that yasm.exe and make.exe are in the bin directory.
  9. Open up a command prompt (programs->accessories->command prompt) and cd c:\camelbox\bin
  10. Run 'perl build.pl' from the command line. The code should compile without errors. (warnings are OK, though)
  11. If you want to change card information (se below) or add a new card, you also have to download SkyMagic Editor. It can be found here. Download it and place it in the same folder as your magic.exe file.

Note: If you have patched your Magic game, some source files in c:\magic\src may be obsolete. To avoid conflicts, it is therefore recommended that the files you copy into c:\camelbox\bin are taken directly from the following folder in the code patch: \magic\zips\magic\src, whenever you use a patched Magic game.

How the program works

The implementation of Magic in this game is basically built around events and triggers. A trigger is generated whenever something happens in the game. For example, a trigger is generated whenever a card is played, whenever damage is dealt and whenever the end of a turn is reached. Events represent the internal state of the game. They are generated, for example, in response to cards being activated, when the game checks for the power of a creature, when a trigger is being created or resolved etc. Once an event or trigger is generated, it is sent to all cards in play. The cards will then respond to the stimuli according to their programming. In other words, programming of the game is centred around getting the cards to respond to whatever happens in the game (represented by triggers and events) in a desired way.

A large number of effects have already been coded in the game as functions. Both the declarations of these functions and the available triggers and events can be found in the manalink.h file, which is located in the src folder of a patched Manalink installation. The definitions of the functions are found in the src/functions folder. The definitions of the cards are found in the src/cards folder.

Because there is no source-code available for the game, all new code operates directly on the exe. One consequence of this is a general slowdown of the game. Another consequence is that the code you write doesn’t always behave as you would expect, even when there are no logical errors in the code. To get around these issues you may have to try several different ways to implement the effects you want to create. Some known problematic code and workarounds are described in the “Known quirks and syntax irregularities”-section below, for the rest you will have to rely on your own wits and creativity. Try to look at how similar problems have been solved in the past, and remember that the most direct route isn’t always the one which will work the best (see the Jester’s Cap loop-code for an example of this).

How to patch the code of an existing card

  1. It is assumed that you have followed the instructions found under the heading of “Getting Started” prior to attempting this.
  2. Find the code for the card you want to modify in the source files located at camelbox\bin\cards.
  3. Update the code for the card. If you need to modify a function, these can (most often) be found in the camelbox\bin\functions folder. If you need to write a new function, place the definition in the camelbox\bin\functions\functions.c file and the declaration in the camelbox\bin\manalink.h file.
  4. When you are satisfied with your changes, you need to compile the code and update the card code used in the magic.exe file. To do this, open up a command prompt (programs->accessories->command prompt) and cd c:\camelbox\bin.
  5. Run 'perl build.pl' from the command line. The code should compile without errors, if not, correct all found errors and try again.
  6. Test your changes in Magic.
    Tip: using the ‘testing’ duel option or the right-click menu in the duels helps speed things up.
  7. Marvel at your own genius or curse the computer’s inability to correctly interpret your beautiful code, depending on the outcome. Reiterate if necessary.

How to change the card information for an existing card

The card information is the part of the card which isn’t affected by its code. Examples of card information are casting cost, card type, card name and rules text. In addition, this is where you will find most of the information that the AI uses to evaluate the cards. By following the steps bellow you can change the card information of existing cards. For a more detailed explanation about the effects of the different types of information available, see the coding cards in assembler tutorial, level 0.

  1. It is assumed that you have followed the instructions found under the heading of “Getting Started” prior to attempting this.
  2. Start the SkyMagic Editor located in the same folder as the magic.exe file of your Magic installation. Make sure that the Manalink.csv tab is open.
  3. Now you must locate the card for which you want to edit the card information. Do this by clicking on the binoculars icon in the top left corner of SkyMagic Editor, then type in the name of the card you are looking for, and finally press enter.
  4. Make the desired changes to the information of the card by editing the values you should now see on the right hand side of the Editor-window.
  5. When you are done with the changes for this card, click the save record button in the bottom centre of the window and select “Yes” when asked if you want to overwrite. If you want to change the information for an additional card, you can do so now by going back to step nr. 3.
  6. When you are done with all changes, press the save button in the top left corner of the Editor-window.
  7. Finally, run the file csv2dat.exe that is located in the same folder as the SkyMagic Editor you used. If no problems are reported, the changes you made have been successfully implemented in your Magic installation.

How to create and add a new card

Now we'll try to add a trivial card, Rorix Bladewing. This same card is added in the tutorial, level 1.

  1. It is assumed that you have followed the instructions found under the heading of “Getting Started” prior to attempting this.
  2. Open src\cards\red_creatures.c in a text editor.
  3. Copy and paste any other card function (they all start with card_), and change the name of the function to card_rorix_bladewing.
  4. Delete all of the code in the card except the function declaration.
  5. Rorix has 2 coded abilities, haste and legend. Open the file manalink.h in the camelbox\bin folder and search for functions named after those abilities, to see if they have already been coded.
  6. You should be able to find coded functions for both abilities, namely void haste(int, int) and void check_legend_rule(int, int, event_t). Therefore you only need to add calls to those functions in your function.
  7. To see what type of arguments should be passed to the functions, you can usually look at the function definitions, found in the camelbox\bin\functions folder. Haste, however, is a function located in the exe. As a result there is no definition in C available for it, so you have to look at how haste has been called in other cards.
  8. Your code should look like:
int card_rorix_bladewing(int player, int card, event_t event){
  check_legend_rule(player, card, event);
  haste(player, card, event);
  return 0;
}
  1. Run build.pl from the command line. Since we are creating a card for the first time, also pass to build the name of the card. I.e. build.pl rorix_bladewing
  2. Note the address at which rorix is added.
  3. Hopefully everything compiled. If not, fix any syntax errors and try again. When you call build, though, do not pass in the name of the card again. That is only required the first time.
  4. Open SkyMagic Editor and add your card. The address mentioned earlier is the code pointer for your card.
  5. Save, run csv2dat, etc. Your card has been added. Congratulations.

Deploying your code

  1. Create a c:\magic\zips folder if it does not already exist.
  2. Run c:\camelbox\bin\deploy.bat (if you are on the command line and in that dir, just type deploy).
  3. A new zip file with today's date will be created in c:\magic\zips

Known quirks and syntax irregularities

  • Before making a player’s library shuffle, you have to make that player gain zero life. If you do not, the library shuffled is often that of the other player! Use the following code to avoid such problems:
gain_life(player, 0);
shuffle(player);
  • Some of the current ability keywords did not exist in the original game, but have been added for convenience. Because of this, they cannot be used in general checks to see if a creature has one of those abilities. For example, in the following code, the if-statement will never be true:
card_data_t card_d = get_card_data(player, card);
if(card_d.static_ability & KEYWORD_LIFELINK){
   life[player] = 1337;
}

For avoiding this, use the function "check_for_ability", that can verify the standard and "fake" keywords.

Programming tips

Debugging

When you test new code you have written for the game, there is often a need to follow the execution of the code, in order to make sure it is working properly (or to find out where things are going wrong). Since there is no C debugger available for the code, you have to use the functions in the game to get the information you need. Some useful ways to get information out of the game are described below. Note, however, that the use of extra functions in your code can sometimes contribute to bugs, so only add them if you need them.

  • Use life[player] or life[opp] to directly change the life of a player. This can be used to confirm that a specific section of the code is reached.
    Examples:
life[player] = 99; // sets the life of the current player to 99
life[opp] += 100; // adds 100 life to the current opponent’s life total
  • If you need to know the value of a specific variable in the game, it can be printed using an in-game dialogue. Do this by using the following code, replacing “PRINT_THIS” with the variable you want to print.
char buffer[50];
sprintf(buffer, " Variable value: %d ", PRINT_THIS);
do_dialog(player, player, card, -1, -1, buffer, 0);

Useful files

When you look at the source for the game, a few files in particular are very important. They are:

  1. manalink.h - This file holds the declarations for all the functions used in the program. It also contains the constants for things like EVENT CODES and CARD STATES. Finally, it holds the data structure for card instances, which comes up in a LOT of code.
  2. manalink.lds - This holds the memory address for all the functions and global variables in Magic.exe. If you are ever trying to read code from Magic.exe, using this as a translation reference is pretty much essential.
  3. ManalinkEh.asm - this file just links up functions you have written to their memory addresses in the dll file that gets loaded by Magic.exe. If you use the build.pl script, your new cards get added to this file automatically. Otherwise, you'll need to update this file manually. The memory addresses must be sequential, 5 bytes apart. If you do use build.pl and make a typo when entering a new card, you'll need to update this file.
  4. functions/functions.c - This holds most of the generic procedures written for cards added in C.