/* * UOX3 Magic stuff */ #include "uox3.h" #include "debug.h" #define DBGFILE "magic.cpp" void spellbook(int s) { int i, j, scount, item, x,serial,serhash,ci; int spells[70]; char sbookstart[8]="\x24\x40\x01\x02\x03\xFF\xFF"; char sbookinit[6]="\x3C\x00\x3E\x00\x03"; char sbookspell[20]="\x40\x01\x02\x03\x1F\x2E\x00\x00\x01\x00\x48\x00\x7D\x40\x01\x02\x03\x00\x00"; item=-1; x=packitem(currchar[s]); serial=items[x].serial; serhash=serial%256; for (ci=0;ci=0x2D && items[j].id2<=0x72) { spells[items[j].id2-0x2D]=1; } } } // Fix for Reactive Armor/Bird's Eye dumbness. :) i=spells[0]; spells[0]=spells[1]; spells[1]=spells[2]; spells[2]=spells[3]; spells[3]=spells[4]; spells[4]=spells[5]; spells[5]=spells[6]; // Morac is right! :) spells[6]=i; // End fix. if (spells[64]) { for (i=0;i<70;i++) spells[i]=1; spells[64]=0; } spells[64]=spells[65]; spells[65]=0; for (i=0;i<70;i++) { if (spells[i]) scount++; } sbookinit[1]=((scount*19)+5)/256; sbookinit[2]=((scount*19)+5)%256; sbookinit[3]=scount/256; sbookinit[4]=scount%256; if (scount>0) xsend(s, sbookinit, 5, 0); for (i=0;i<70;i++) if (spells[i]) { sbookspell[0]=0x41; sbookspell[1]=0x00; sbookspell[2]=0x00; sbookspell[3]=i+1; sbookspell[8]=i+1; sbookspell[13]=items[item].ser1; sbookspell[14]=items[item].ser2; sbookspell[15]=items[item].ser3; sbookspell[16]=items[item].ser4; xsend(s, sbookspell, 19, 0); } // xsend(s, restart, 2, 0); } void recall(int s) { int i,serial; int recalled=0; serial=calcserial(buffer[s][7],buffer[s][8],buffer[s][9],buffer[s][10]); i=findbyserial(&itemsp[serial%256], serial, 0); if ((i!=-1) && (items[i].type==50)) { if (items[i].morex==0 && items[i].morey==0 && items[i].morez==0) { sysmessage(s,"That rune has not been marked yet!"); } soundeffect(s, 0x01, 0xFC); chars[currchar[s]].x=items[i].morex; chars[currchar[s]].y=items[i].morey; chars[currchar[s]].dispz=chars[currchar[s]].z=items[i].morez; teleport(currchar[s]); sysmessage(s,"You have recalled from the rune."); recalled=1; } if(!recalled) sysmessage(s,"That item is not a recall rune."); } void mark(int s) { int i,serial; int marked=0; serial=calcserial(buffer[s][7],buffer[s][8],buffer[s][9],buffer[s][10]); i=findbyserial(&itemsp[serial%256], serial, 0); if ((i!=-1) && (items[i].type==50)) { if ((line_of_sight(calcSocketFromChar(s),chars[currchar[s]].x,chars[currchar[s]].y,chars[currchar[s]].z,items[i].x,items[i].y,items[i].z,WALLS_CHIMNEYS+DOORS+FLOORS_FLAT_ROOFING)|| (chars[currchar[s]].priv&0x01))) { soundeffect(s, 0x01, 0xFA); items[i].morex=chars[currchar[s]].x; items[i].morey=chars[currchar[s]].y; items[i].morez=chars[currchar[s]].z; sysmessage(s,"Recall rune marked."); marked=1; } else { sysmessage(s, "** Wishing I could see it so I COULD mark it **"); marked=1; } } if(!marked) sysmessage(s,"That item is not a recall rune."); } char gate(int s) { int i,n,c,serial; unsigned int j; char gated=0; serial=calcserial(buffer[s][7],buffer[s][8],buffer[s][9],buffer[s][10]); i=findbyserial(&itemsp[serial%256], serial, 0); if ((i!=-1) && (items[i].type==50)) { gatex[gatecount][0]=chars[currchar[s]].x+1; gatey[gatecount][0]=chars[currchar[s]].y+1; gatez[gatecount][0]=chars[currchar[s]].z; gatex[gatecount][1]=items[i].morex; gatey[gatecount][1]=items[i].morey; gatez[gatecount][1]=items[i].morez; gated=1; } if(!gated) { sysmessage(s,"You cannot gate from that item."); return(0); } soundeffect(s, 0x02, 0x0E); for (n=0;n<2;n++) { sprintf(temp,"a blue moongate"); c=SpawnItem(s,1,"#",0,0x0f,0x6c,0,0,0,0); items[c].type=51+n; items[c].x=gatex[gatecount][n]; items[c].y=gatey[gatecount][n]; items[c].z=gatez[gatecount][n]; items[c].gatetime=(getclock()+(server_data.gatetimer*CLOCKS_PER_SEC)); items[c].gatenumber=gatecount; items[c].dir=1; for (j=0;jMAXGATES) gatecount=0; } addid1[s]=0; addid2[s]=0; } return(1); } char gatecollision(int s) { unsigned int i,n; for (i=0;i=items[i].z)) { chars[s].x=gatex[items[i].gatenumber][n]+1; chars[s].y=gatey[items[i].gatenumber][n]; chars[s].dispz=chars[s].z=gatez[items[i].gatenumber][n]; teleport(s); } } } return(1); } void gatedestruction(unsigned int currenttime) { unsigned int i,k; for (i=0;i0 ) // to see if is same item we click on in case of spell type = 2 if (!((items[Numitem].contserial==chars[currchar[s]].serial) && (items[Numitem].layer==2||items[Numitem].layer==1 ))) { sysmessage(s,"You cannot cast with a weapon equipped."); return 0; } } } } if ((chars[currchar[s]].hidden)&&(!(chars[currchar[s]].priv2&8))) { chars[currchar[s]].hidden=0; updatechar(currchar[s]); } // Mana not necessary if wand or staff or GM otherwise check mana if (type != 2) { if ((chars[currchar[s]].mn < mana) && !(chars[currchar[s]].priv2&0x01)) { success=0; sysmessage(s, "You have insufficient mana to cast that spell."); } } else success=1; if (!success) return 0; //Check for enough reagents if (type==0 && (!checkreagents(currchar[s], ash, drake, garlic, ginsing, moss, pearl, shade, silk))) { return 0; } //Only speak if not a rod/staff/wand if (type!=2) { impaction(s, action); npctalkall(currchar[s], mantra); } //Use Reagents Use them regarless of success or failure if (type==0) { delereagents(currchar[s], ash, drake, garlic, ginsing, moss, pearl, shade, silk); } //Check success of casting Except for GM's if (type!=2 && !(chars[currchar[s]].priv2&0x01) && !checkskill(currchar[s], MAGERY, loskill, hiskill)) { spellfail(s); return 0; } //subtract mana we know they have enough mana at this point if (success && type!=2) success=subtractmana(currchar[s], mana); //spell section for implementation specific stuff to get the spell to work switch (num) { case 1: // Clumsy target(s,0,1,0,100,"Select target for clumsy."); break; case 2: // Create Food target(s,0,1,0,54,"Select location for food."); break; case 3: // Feeblemind target(s,0,1,0,101,"Select target for feeblemind."); break; case 4: // Heal target(s,0,1,0,83,"Select person to heal."); break; case 5: // Magic Arrow target(s,0,1,0,68,"Select target for magic arrow."); break; case 6: // Night Sight target(s,0,1,0,99,"Select target for night sight."); break; case 7: // Reactive Armor reactivearmortarget(s); break; case 8: // Weaken target(s,0,1,0,102,"Select target for weaken."); break; case 9: // Agility target(s,0,1,0,103,"Select target for agility."); break; case 10:// Cunning target(s,0,1,0,104,"Select target for cunning."); break; case 11:// Cure target(s,0,1,0,182,"Select target to cure."); break; case 12:// Harm target(s,0,1,0,85,"Select target for harm."); break; case 13://Magic Trap target(s,0,1,0,196,"Select item to set magic trap."); break; case 14://Magic Untrap target(s,0,1,0,197,"Select item to untrap."); break; case 16: // Strength target(s,0,1,0,105,"Select target for strength."); break; case 17:// Bless target(s,0,1,0,124,"Select target for bless."); break; case 18:// Fireball target(s,0,1,0,74,"Select target for fireball."); break; case 19://Magic Lock target(s,0,1,0,195,"Select item to lock."); break; case 20:// Poison target(s,0,1,0,181,"Select target to Poison."); break; case 22:// Teleport target(s,0,1,0,2,"Select target for teleport."); break; case 23:// Unlock addmitem[s]= -1; target(s,0,1,0,162,"What do you want to unlock?"); break; case 24:// Wall of Stone target(s,0,1,0,92,"Select location for wall of stone."); break; case 25://Arch Cure target(s,0,1,0,192,"Select location for Arch Cure."); break; case 27:// Curse target(s,0,1,0,125,"Select target for curse."); break; case 28:// Fire Field target(s,0,1,0,91,"Select location for fire field."); break; case 29:// Greater Heal target(s,0,1,0,84,"Select person to heal."); break; case 30:// Lightning target(s,0,1,0,73,"Select target for lightning."); break; case 31://Mana drain target(s,0,1,0,188,"Select target for Mana Drain."); break; case 32:// Recall if (!(region[chars[currchar[s]].region].priv&0x08)) { sysmessage(s, "You may not cast recall in this region."); if (chars[s].priv2&0x10) { success=1; break; } chars[s].mn+=mana; success=0; } else target(s,0,1,0,38,"Select rune from which to recall."); break; case 33:// Blade Spirits target(s,0,1,0,70, "Select location for blade spirits."); break; case 34:// Dispel Field target(s,0,1,0,95, "Select field to dispel."); break; case 36:// Magic Reflection magicreflectiontarget(s); break; case 37:// Mind Blast target(s,0,1,0,97, "Select target for mind blast."); break; case 38:// Paralyze target(s,0,1,0,96, "Select target for paralyze."); break; case 39:// Poison Field target(s,0,1,0,98 , "Select location for poison field."); break; case 41:// Dispel target(s,0,1,0,90,"Select target to dispel."); break; case 42:// Energy Bolt target(s,0,1,0,75,"Select target for energy bolt."); break; case 43://Explosion target(s,0,1,0,72, "Select target for explosion"); break; case 44:// Invisibility target(s,0,1,0,67,"Select character to make invisible."); break; case 45:// Mark if (!(region[chars[currchar[s]].region].priv&0x02)) { sysmessage(s, "You may not cast mark in this region."); if (chars[s].priv2&0x10) { success=0; break; } chars[s].mn+=mana; success=0; } else target(s,0,1,0,39,"Select rune to mark."); break; case 46:// Mass curse target(s,0,1,0,193,"Select location for Mass Curse."); break; case 47:// Paralyze Field target(s,0,1,0,93,"Select location for paralyze field."); break; case 48:// Reveal target(s,0,1,0,78,"Select area to reveal."); break; case 49:// Chain Lightning target(s,0,1,0,191,"Select location for Chain Lightning."); break; case 50:// Energy Field target(s,0,1,0,94,"Select location for energy field."); break; case 51:// Flamestrike target(s,0,1,0,71,"Select player to flamestrike."); break; case 52:// Gate Travel if (!(region[chars[currchar[s]].region].priv&0x04)) { sysmessage(s, "You may not cast gate travel in this region."); if (chars[s].priv2&0x10) { success=0; break; } chars[s].mn+=mana; success=0; } else target(s,0,1,0,43,"Select rune from which to gate.");//gate(s); break; case 53://Mana Vampire target(s,0,1,0,189,"Select target for Mana Vampire."); break; case 54://Mass Dispel target(s,0,1,0,194,"Select location for Mass Dispel."); break; case 55://Meteor Swarm target(s,0,1,0,190,"Select location for Meteor Swarm."); break; case 58:// Energy Vortex target(s,0,1,0,69,"Select location for energy vortex."); break; case 59:// Resurrection target(s,0,1,0,21,"Select ghost to resurrect."); //resurrect(s); break; case 60:// Summon Air Elemental summonmonster(s, 0x00, 0x0d, "air"); break; case 61:// Summon Daemon summonmonster(s, 0x00, 0x0A, "daemon"); break; case 62:// Summon Earth Elemental summonmonster(s, 0x00, 0x0e, "earth"); break; case 63:// Summon Fire Elemental summonmonster(s, 0x00, 0x0f, "fire"); break; case 64:// Summon Water Elemental summonmonster(s, 0x00, 0x10, "water"); break; case 65:// Summon Hero summonmonster(s, 0x01, 0x90, "Death Knight"); break; case 66://Cannon Firing target(s,0,1,0,169, "Aye Aye Sir cannon is loaded, please select your target"); break; default: impaction(s,0x11); // Unimplemented Spells } if (success) return 1; if (!success) spellfail(s); return 0; } void summonmonster(int s, char id1, char id2, char * monstername, char color1, char color2, int x, int y, int z) { int i; unsigned int c; c=memcharfree (); i=(id1*256)+id2; initchar(c); switch(i) { case 0x000D: // Energy Vortex & Air elemental if (color1==0x00 && color2==0x75) { soundeffect(s, 0x02, 0x16); // EV chars[c].def=22; chars[c].lodamage=20; chars[c].hidamage=30; //chars[c].spattack=8191; // 1-7 level spells chars[c].baseskill[MAGERY]=950; // 95 magery chars[c].baseskill[TACTICS]=800; // 80 tactics chars[c].skill[MAGICRESISTANCE]=750; chars[c].st=chars[c].hp=600; chars[c].dx=chars[c].stm=160; chars[c].in=chars[c].mn=180; chars[c].npcWander=2; chars[c].npcaitype=30; chars[c].poison=3; // chars[c].npcaitype=0x08; } else { soundeffect(s, 0x02, 0x17); // AE chars[c].def=19; chars[c].lodamage=5; chars[c].hidamage=13; chars[c].spattack=4095; // 1-6 level spells chars[c].baseskill[MAGERY]=750; // 75 magery chars[c].baseskill[TACTICS]=700; // 70 tactics chars[c].skill[MAGICRESISTANCE]=450; chars[c].st=chars[c].hp=125; chars[c].dx=chars[c].stm=100; chars[c].in=chars[c].mn=80; } break; case 0x000A: // Daemon soundeffect(s, 0x02, 0x16); chars[c].def=20; chars[c].lodamage=10; chars[c].hidamage=45; chars[c].spattack=8191; // 1-7 level spells chars[c].baseskill[MAGERY]=900; // 90 magery chars[c].baseskill[TACTICS]=700; // 70 tactics chars[c].skill[MAGICRESISTANCE]=650; chars[c].st=chars[c].hp=600; chars[c].dx=chars[c].stm=70; chars[c].in=chars[c].mn=100; break; case 0x000E: //Earth soundeffect(s, 0x02, 0x17); chars[c].def=15; chars[c].lodamage=3; chars[c].hidamage=18; chars[c].baseskill[TACTICS]=850; // 85 tactics chars[c].skill[MAGICRESISTANCE]=350; chars[c].st=chars[c].hp=125; chars[c].dx=chars[c].stm=90; chars[c].in=chars[c].mn=70; break; case 0x000F: //Fire case 0x0010: //Water soundeffect(s, 0x02, 0x17); chars[c].def=19; chars[c].lodamage=4; chars[c].hidamage=12; chars[c].spattack=4095; // 1-6 level spells chars[c].baseskill[MAGERY]=800; // 80 magery chars[c].baseskill[TACTICS]=800; // 80 tactics chars[c].skill[MAGICRESISTANCE]=450; chars[c].st=chars[c].hp=120; chars[c].dx=chars[c].stm=95; chars[c].in=chars[c].mn=70; break; case 0x023E: //Blade Spirits soundeffect(s, 0x02, 0x12); // I don't know if this is the right effect... chars[c].def=24; chars[c].lodamage=5; chars[c].hidamage=10; chars[c].baseskill[TACTICS]=950; // 95 tactics chars[c].skill[MAGICRESISTANCE]=650; chars[c].st=chars[c].hp=200; chars[c].dx=chars[c].stm=95; chars[c].in=chars[c].mn=70; chars[c].npcWander=2; chars[c].npcaitype=30; chars[c].poison=1; break; case 0x0190: // Death Knight soundeffect(s, 0x02, 0x46); chars[c].def=20; chars[c].lodamage=10; chars[c].hidamage=45; chars[c].spattack=4095; // 1-7 level spells chars[c].baseskill[MAGERY]=500; // 90 magery chars[c].baseskill[TACTICS]=1000; // 70 tactics chars[c].baseskill[SWORDSMANSHIP]=1000; chars[c].baseskill[PARRYING]=1000; chars[c].skill[MAGICRESISTANCE]=650; chars[c].st=chars[c].hp=600; chars[c].dx=chars[c].stm=70; chars[c].in=chars[c].mn=100; chars[c].fame=-10000; chars[c].karma=-10000; break; default: soundeffect(s, 0x02, 0x15); } sprintf(chars[c].name, monstername); chars[c].id1=id1; chars[c].id2=id2; chars[c].xid1=id1; chars[c].xid2=id2; chars[c].skin1=color1; chars[c].skin2=color2; chars[c].xskin1=color1; chars[c].xskin2=color2; chars[c].priv2=0x20; chars[c].npc=1; if (i!=0x023E && !(i==0x000d && color1==0 && color2==0x75)) // don't own BS or EV. /* chars[c].own1=chars[currchar[s]].ser1; chars[c].own2=chars[currchar[s]].ser2; chars[c].own3=chars[currchar[s]].ser3; chars[c].own4=chars[currchar[s]].ser4;*/ setserial(c, currchar[s], 5); if (x==0) { chars[c].x=chars[currchar[s]].x-1; chars[c].y=chars[currchar[s]].y; chars[c].dispz=chars[c].z=chars[currchar[s]].z; } else { chars[c].x=x; chars[c].y=y; chars[c].dispz=chars[c].z=z; } chars[c].spadelay=10; chars[c].summontimer=(getclock()+((chars[currchar[s]].skill[MAGERY]/10)*(CLOCKS_PER_SEC*2)));//60))); if (c==charcount) { charcount++; charcount2++; } updatechar(c); npcaction(c, 0x0C); } int checkBook(int circle, int spell, int i) { int j, spellnum, raflag=0,serial,serhash,ci; spellnum=spell+(circle-1)*8; // Fix for OSI stupidity. :) if (spellnum==6) raflag=1; if (spellnum>=0 && spellnum<6) spellnum++; if (raflag) spellnum=0; serial=items[i].serial; serhash=serial%256; //j=findbyserial(&itemsp[serial%256], serial,0); /*for (j=0;j