Portals part 5

I finally got around to adding the “portal” spell, which allows players to target a player or NPC and create a 2-way portal.  I’ll include the code below the jump.

My first thoughts in creating the portal spell was to use the spell template for creating objects, MAG_CREATIONS.  However, if you look at the code within MAGIC.C, you’ll find that MAG_CREATIONS really doesn’t give us a whole lot of customizable options.  The function receives, as inputs, the spell level, character casting the spell, and the number of the spell (as defined in SPELLS.H).  No information about a target is passed because the creation spells are intended to just create a static object.

So instead of messing with the MAG_CREATIONS function, I decided to make the portal skill a manual spell, with it’s own ASPELL() function in SPELLS.C.

Here’s the code:

ASPELL(spell_portal)
{
/*  struct obj_data *j; */
obj_rnum r_num;
obj_vnum portal_vnum = 197;  /* This is the default portal object. */

if (ch == NULL || victim == NULL)
return;

if (GET_LEVEL(victim) > MIN(LVL_IMMORT -1, level + 3)) {
send_to_char(ch, “You failed.\r\n”);
return;
}

/* We will use NO_SUMMON for portaling as well as summoning.  May add a “NOPORTAL” flag in the future */

if (!CONFIG_PK_ALLOWED) {
if (!IS_NPC(victim) && !PRF_FLAGGED(victim, PRF_SUMMONABLE) &&
!PLR_FLAGGED(victim, PLR_KILLER)) {
send_to_char(victim, “%s just tried to create a portal to you.\r\n”
“%s failed because you have summon protection on.\r\n”
“Type NOSUMMON to allow other players to create a portal to you.\r\n”,
GET_NAME(ch), (ch->player.sex == SEX_MALE) ? “He” : “She”);

send_to_char(ch, “You failed because %s has summon protection on.\r\n”, GET_NAME(victim));
mudlog(BRF, LVL_IMMORT, TRUE, “%s failed creating a portal to %s in %s.”, GET_NAME(ch), GET_NAME(victim), world[IN_ROOM(ch)].name);
return;
}
}

if (MOB_FLAGGED(victim, MOB_NOSUMMON) ||
(IS_NPC(victim) && mag_savingthrow(victim, SAVING_SPELL, 0))) {
send_to_char(ch, “You failed.”);
return;
}

if (IN_ROOM(victim) == NOWHERE || IN_ROOM(ch) == NOWHERE) {
send_to_char(ch, “Room is NOWHERE tell an immortal STAT!”);
return;
}

/* The spell has succeeded, what now? */
/* create the object in the character’s room */
r_num = real_object(portal_vnum);
obj = read_object(r_num, REAL);
obj_to_room(obj, IN_ROOM(ch));

/* Set the portal’s target vnum to the victim’s room VNUM */
GET_OBJ_VAL(obj, 0) = GET_ROOM_VNUM(IN_ROOM(victim));
/* Set the portal’s level value to the caster’s LEVEL/2 */
GET_OBJ_VAL(obj, 1) = GET_LEVEL(ch) / 2;

/* Set a timer on the portal, it will disappear after some time */
GET_OBJ_TIMER(obj) = 6;

/* Send success messages to the caster */
act(“$n creates a rift in time and space.”, TRUE, ch, 0, 0, TO_ROOM);

/* Create the same object in the victim’s room, pointing back to the caster’s room */
/* We may be able to get rid of the first two lines here, but keep them in to be safe */
r_num = real_object(portal_vnum);
obj = read_object(r_num, REAL);
obj_to_room(obj, IN_ROOM(victim));

/* Set the portal’s target room to the ch’s VNUM */
GET_OBJ_VAL(obj, 0) = GET_ROOM_VNUM(IN_ROOM(ch));

/* Set the portal’s level to the caster’s level/2 */
GET_OBJ_VAL(obj, 1) = GET_LEVEL(ch) / 2;

/* Set a timer on the portal, it will disappear after some time */
GET_OBJ_TIMER(obj) = 6;

/* Send messages to the victim */
act(“A portal appears in front of you!”, TRUE, victim, 0, 0, TO_ROOM);
act(“A portal appears out of nowhere!”, FALSE, victim, 0, victim, TO_VICT);

return;
}

Here’s the definition in SPELL_PARSER.C where manual spells are called:

case SPELL_PORTAL:          MANUAL_SPELL(spell_portal); break;

Also, later on in SPELL_PARSER.C it is important to add the spello() call:

spello(SPELL_PORTAL, “portal”, 200, 150, 10, POS_STANDING,
TAR_CHAR_WORLD | TAR_NOT_SELF, FALSE, MAG_MANUAL, NULL);

And don’t forget in SPELLS.H to assign the spell to a number, in my case it is 79:

#define SPELL_PORTAL             79

and later on in SPELLS.H, declare the ASPELL() function (otherwise we get an error on compile):

ASPELL(spell_portal);

That should just about do it.  Of course, you still have to assign the portal spell to a class (in CLASS.C), e.g.:

spell_level(SPELL_PORTAL, CLASS_MAGIC_USER, 30);

Oh, and I’ll admit that the code for the spell could likely be done a whole lot nicer.  I’m not a professional coder, so the fact that I got it running is enough for me.  I also could have drastically reworked MAG_CREATIONS() to make portal fit under that standard, but I figured that would be a hassle.  However, since I am planning on implementing more object creation spells, at some point I’ll have to delve into that bit of code and work out what exactly I need it to do.

But for now, ASPELL(spell_portal) works, which is a good start.

Leave a comment