Reorganizes Project (#41)

This commit is contained in:
Kamron Batman 2019-08-02 18:13:40 -07:00 • committed by GitHub
parent 08bf44af9a
commit 3614a66aee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3499 changed files with 79 additions and 55 deletions

View file

@ -0,0 +1,776 @@
namespace Server.Items
{
public class GrimmochJournal1 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day One :",
"",
"'Tis a grand sight, this",
"primeval tomb, I agree",
"with Tavara on that.",
"And we've a good crew",
"here, they've strong",
"backs and a good"
),
new BookPageInfo
(
"attitude. I'm a bit",
"concerned by those",
"that worked as guides",
"for us, however. All",
"seemed well enough",
"until we revealed the",
"immense stone doors",
"of the tomb structure"
),
new BookPageInfo
(
"itself. Seemed to send",
"a shiver up their",
"spines and get them all",
"stirred up with",
"whispering. I'll",
"watch the lot of them",
"with a close eye, but",
"I'm confident we won't"
),
new BookPageInfo
(
"have any real",
"problems on the dig.",
"I'm especially proud to",
"see Thomas standing",
"out - he was a good",
"hire, despite the",
"warnings from his",
"previous employers."
),
new BookPageInfo
(
"He's drummed up the",
"workers into a",
"furious pace - we've",
"nearly halved the",
"estimate on the",
"timeline for",
"excavating the Tomb's",
"entrance."
)
);
[Constructible]
public GrimmochJournal1() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal1(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal2 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Two :",
"",
"We managed to dig out",
"the last of the",
"remaining rubble",
"today, revealing the",
"entirety of the giant",
"stone doors that sealed"
),
new BookPageInfo
(
"ol' Khal Ankur and",
"his folk up ages ago.",
"Actually getting them",
"open was another",
"matter altogether,",
"however. As the",
"workers set to the",
"task with picks and"
),
new BookPageInfo
(
"crowbars, I could have",
"sworn I saw Lysander",
"Gathenwale fiddling",
"with something in that",
"musty old tome of his.",
" I've no great",
"knowledge of things",
"magical, but the way"
),
new BookPageInfo
(
"his hand moved over",
"that book, and the look",
"of concentration on his",
"face as he whispered",
"something to himself",
"looked like every",
"description of an",
"incantation I've ever"
),
new BookPageInfo
(
"heard. The strange",
"thing is, this set of",
"doors that an entire",
"crew of excavators",
"was laboring over for",
"hours, right when",
"Gathenwale finishes",
"with his mumbling..."
),
new BookPageInfo
(
"well, I swore the doors",
"just gave open at the",
"exact moment he",
"spoke his last bit of",
"whisper and shut the",
"tome tight in his",
"hands. When he",
"looked up, it was"
),
new BookPageInfo
(
"almost as if he was",
"expecting the doors to",
"be open, rather than",
"shocked that they'd",
"finally given way."
)
);
[Constructible]
public GrimmochJournal2() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal2(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal3 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Three - Day Five:",
"",
"I might have",
"written too hastily in",
"my first entry - this",
"place doesn't seem too",
"bent on giving up any",
"secrets. Though the"
),
new BookPageInfo
(
"main antechamber is",
"open to us, the main",
"exit hall is blocked by",
"yet another pile of",
"rubble. Doesn't look a",
"bit like anything",
"caused by a quake or",
"instability in the"
),
new BookPageInfo
(
"stonework... I swear it",
"looks as if someone",
"actually piled the",
"stones up themselves,",
"some time after the",
"tomb was built. The",
"stones aren't of the",
"same set nor quality"
),
new BookPageInfo
(
"of the carved work",
"that surrounds them",
"- if anything, they",
"resemble the grade of",
"common rock we saw",
"in great quantities on",
"the trip here. Which",
"makes it feel all the"
),
new BookPageInfo
(
"more like someone",
"hauled them in and",
"deliberately covered",
"this passage. But then",
"why not decorate them",
"in the same ornate",
"manner as the rest of",
"the stone in this"
),
new BookPageInfo
(
"place? Lysander",
"wouldn't hear a word",
"of what I had to say -",
"to him, it was a quake",
"some time in the",
"history of the tomb,",
"and that was it, shut",
"up and move on. So I"
),
new BookPageInfo
(
"shut up, and got back",
"to work."
)
);
[Constructible]
public GrimmochJournal3() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal3(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal6 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Six :",
"",
"The camp was",
"attacked last night by",
"a pack of, well, I don't",
"have a clue. I've never",
"seen the like of these",
"beasts anywhere."
),
new BookPageInfo
(
"Huge things, with",
"fangs the size of your",
"forefinger, covered in",
"hair and with the",
"strangest arched back",
"I've ever seen. And so",
"many of them. We",
"were forced back into"
),
new BookPageInfo
(
"the Tomb for the",
"night, just to keep our",
"hides on us. And",
"today Gathenwale",
"practically orders us",
"all to move the entire",
"exterior camp into the",
"Tomb. Now, I don't"
),
new BookPageInfo
(
"disagree that we'd be",
"well off to use the",
"place as a point of",
"fortification... but I",
"don't like it one bit, in",
"any case. I don't like",
"the look of this place,",
"nor the sound of it."
),
new BookPageInfo
(
"The way the wind",
"gets into the",
"passageways,",
"whistling up the",
"strangest noises.",
"Deep, sustained echoes",
"of the wind, not so",
"much flute-like as..."
),
new BookPageInfo
(
"well, it sounds",
"ridiculous. In any",
"case, we've set to work",
"moving the bulk of the",
"exterior camp into the",
"main antechamber, so",
"there's no use moaning",
"about it now."
)
);
[Constructible]
public GrimmochJournal6() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal6(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal7 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Seven - Day Ten:",
"",
"I cannot stand this",
"place, I cannot bear it.",
"I've got to get out.",
"Something evil lurks",
"in this ancient place,",
"something best left"
),
new BookPageInfo
(
"alone. I hear them,",
"yet none of the others",
"do. And yet they",
"must. Hands, claws,",
"scratching at stone,",
"the awful scratching",
"and the piteous cries",
"that sound almost like"
),
new BookPageInfo
(
"laughter. I can hear",
"them above even the",
"cracks of the",
"workmen's picks, and",
"at night they are all I",
"can hear. And yet the",
"others hear nothing.",
"We must leave this"
),
new BookPageInfo
(
"place, we must.",
"Three workers have",
"gone missing - Tavara",
"expects they've",
"abandoned us - and I",
"count them lucky if",
"they have. I don't care",
"what the others say,"
),
new BookPageInfo
(
"we must leave this",
"place. We must do as",
"those before and pile",
"up the stones, block all",
"access to this primeval",
"crypt, seal it up again",
"for all eternity."
)
);
[Constructible]
public GrimmochJournal7() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal7(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal11 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Eleven - Day",
"Thirteen :",
"",
"Lysander is gone, and",
"two more workers",
"with him. Good",
"riddance to the first.",
"He knows something."
),
new BookPageInfo
(
"He heard them too, I",
"know he did - and yet",
"he scowled at me",
"when I mentioned",
"them. I cannot stop",
"the noise in my head,",
"the scratching, the",
"clawing tears at my"
),
new BookPageInfo
(
"senses. What is it?",
"What does Lysander",
"seek that I can only",
"turn from? Where",
"has he gone? The",
"only answer to my",
"questions comes as",
"laughter from behind"
),
new BookPageInfo
(
"the stones."
)
);
[Constructible]
public GrimmochJournal11() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal11(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal14 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Fourteen - Day",
"Sixteen :",
"",
"We are lost... we are",
"lost... all is lost. The",
"dead are piled up at",
"my feet. Bergen and I",
"somehow managed in"
),
new BookPageInfo
(
"the madness to piece",
"together a barricade,",
"barring access to the",
"camp antechamber.",
"He knows as well as I",
"that we cannot hold it",
"forever. The dead",
"come. They took"
),
new BookPageInfo
(
"Lysander before our",
"eyes. I pity the soul",
"of even such a",
"madman - no one",
"should die in such a",
"manner. And yet so",
"many have. We're",
"trapped here in this"
),
new BookPageInfo
(
"horror. So many have",
"died, and for what?",
"What curse have we",
"stumbled upon? I",
"cannot bear it, the",
"moaning, wailing cries",
"of the dead. Poor",
"Thomas, cut to pieces"
),
new BookPageInfo
(
"by their blades. We",
"had only an hour to",
"properly bury those",
"we could, before the",
"undead legions struck",
"again. I cannot go on...",
"I cannot go on."
)
);
[Constructible]
public GrimmochJournal14() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal14(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal17 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Seventeen - Day",
"Twenty-Two :",
"",
"The fighting never",
"ceases... the blood",
"never stops flowing,",
"like a river through",
"the bloated corpses of"
),
new BookPageInfo
(
"the dead. And yet",
"there are still more.",
"Always more, with",
"the red fire gleaming",
"in their eyes. My",
"arm aches, I've taken",
"to the sword as my",
"bow seems to do little"
),
new BookPageInfo
(
"good... the dull ache in",
"my arm... so many",
"swings, cleaving a",
"mountain of decaying",
"flesh. And Thomas...",
"he was there, in the",
"thick of it... Thomas",
"was beside me..."
),
new BookPageInfo
(
"his face cleaved in",
"twain - and yet beside",
"me, fighting with us",
"against the horde until",
"he was cut down once",
"again. And I swear I",
"see him even now,",
"there in the dark"
),
new BookPageInfo
(
"corner of the",
"antechamber, his eyes",
"flickering in the last",
"dying embers of the",
"fire... and he stares at",
"me, and a scream fills",
"the vault - whether",
"his or mine, I can no"
),
new BookPageInfo
(
"longer tell."
)
);
[Constructible]
public GrimmochJournal17() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal17(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class GrimmochJournal23 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"The daily journal of Grimmoch Drummel", "Grimmoch",
new BookPageInfo
(
"Day Twenty-Three :",
"",
"We no longer bury the",
"dead."
)
);
[Constructible]
public GrimmochJournal23() : base(Utility.Random(0xFF1, 2), false)
{
}
public GrimmochJournal23(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,536 @@
namespace Server.Items
{
public class LysanderNotebook1 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"Lysander's Notebook", "L. Gathenwale",
new BookPageInfo
(
"Day One :",
"",
"At last, it stands",
"before me. The doors",
"of Thy Sanctum will",
"open to me now, after",
"all these years of",
"searching. I give"
),
new BookPageInfo
(
"myself unto Thee,",
"Khal Ankur, I have",
"come for Thy secrets",
"and I will kneel",
"prostrate before Thee.",
" Blessed are the",
"Keepers, praise unto",
"Thee, a thousand"
),
new BookPageInfo
(
"fortunes in the night."
)
);
[Constructible]
public LysanderNotebook1() : base(Utility.Random(0xFF1, 2), false)
{
}
public LysanderNotebook1(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class LysanderNotebook2 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"Lysander's Notebook", "L. Gathenwale",
new BookPageInfo
(
"Day Two:",
"",
"The woman, Tavara",
"Sewel, is unbearable.",
"Her entire demeanor",
"sickens me. I would",
"take her life for Thee",
"now, my Lord. But I"
),
new BookPageInfo
(
"cannot alert the",
"others. Progress is",
"made too slowly, I",
"cannot stand this",
"perpetual waiting.",
"Today I knelt down",
"with the workers,",
"tossing stones and dirt"
),
new BookPageInfo
(
"aside with my very",
"hands as they dug at",
"the last of the rubble",
"covering the entrance",
"to Thy Sanctum. The",
"Sewel woman was",
"shocked at my",
"demeanor, dirtying"
),
new BookPageInfo
(
"my robes, on my",
"knees in the muck as I",
"clawed at the rocks.",
"She thought I did this",
"for those sickly",
"scholars, or for her,",
"or for what she",
"laughably calls 'The"
),
new BookPageInfo
(
"Gift of Discovery', of",
"learning. As if I did",
"not know what I went",
"to find! I come for",
"Thee, Master. Soon",
"shall I receive Thy",
"gifts, Thy blessings.",
"Patience, eternal"
),
new BookPageInfo
(
"patience. I must take",
"my lessons well. I",
"have learned from",
"Thee, Master, I have."
)
);
[Constructible]
public LysanderNotebook2() : base(Utility.Random(0xFF1, 2), false)
{
}
public LysanderNotebook2(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class LysanderNotebook3 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"Lysander's Notebook", "L. Gathenwale",
new BookPageInfo
(
"Day Three - Day Six:",
"",
"What are these Beasts",
"that dare to defy our",
"presence here? Hast",
"Thou sent them,",
"Master? To tear",
"apart these foolish"
),
new BookPageInfo
(
"ones that accompany",
"me? That repugnant",
"pustule, Drummel, put",
"forth his absurd little",
"theories as to the",
"nature of the Beasts",
"that attacked our",
"camp, but I'll have"
),
new BookPageInfo
(
"none of his words. He",
"asks too many",
"questions. He is a",
"taint upon the grounds",
"of Thy Sanctum,",
"Master - I will deal",
"with him after the",
"Sewel woman."
),
new BookPageInfo
(
"Speaking of Sewel, I",
"have convinced that",
"empty-headed harlot",
"that we should move",
"our encampment",
"within the",
"antechamber. She",
"thinks I worry for"
),
new BookPageInfo
(
"her safety. I come",
"for thee, Master. I",
"make my camp in Thy",
"chambers. I sleep",
"under Thy roof. I can",
"feel Thine presence",
"even now. Soon,",
"Master. Soon."
)
);
[Constructible]
public LysanderNotebook3() : base(Utility.Random(0xFF1, 2), false)
{
}
public LysanderNotebook3(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class LysanderNotebook7 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"Lysander's Notebook", "L. Gathenwale",
new BookPageInfo
(
"Day Seven :",
"",
"The Sewel woman",
"pratters on endlessly.",
"And she dares to",
"speak Thy Name,",
"Master! I wish so",
"vehemently to take a"
),
new BookPageInfo
(
"knife to that little",
"neck of hers. She",
"struts around the",
"chambers of Thy",
"Sanctum with her",
"repugnant airs, her",
"scholarly conjecture",
"on this or that. That I"
),
new BookPageInfo
(
"could peel the skin",
"from her face and",
"show her how vile and",
"ugly she truly is, how",
"unworthy of entrance",
"to Thy Sanctum. I",
"must take her,",
"Master. I must rend"
),
new BookPageInfo
(
"that little wench to",
"pieces. I ask this gift",
"of Thee, that I might",
"cleanse Thy Sanctum",
"of her presence. Give",
"me the Sewel woman",
"and I shall show you",
"my mastery of Death,"
),
new BookPageInfo
(
"Master. I shall cut",
"her to bits and scatter",
"them before the",
"others as a warning.",
"I cannot stand her",
"presence, I cannot",
"abide it. And",
"Drummel! He is a"
),
new BookPageInfo
(
"pustule that must be",
"lanced, a sickness that",
"I must cure by blade",
"and fire. Not a trace",
"of him will be left",
"when I'm done with",
"him. Praises to Thee,",
"Master. I shall honor"
),
new BookPageInfo
(
"Thee with many",
"sacrifices, soon",
"enough."
)
);
[Constructible]
public LysanderNotebook7() : base(Utility.Random(0xFF1, 2), false)
{
}
public LysanderNotebook7(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class LysanderNotebook8 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"Lysander's Notebook", "L. Gathenwale",
new BookPageInfo
(
"Day Eight - Day Ten :",
"",
"Have you taken them,",
"Master? They could",
"not have found a way",
"past the stones that",
"block our path! The",
"three workers, My"
),
new BookPageInfo
(
"Master, where have",
"they gone? Curses",
"upon them! I'll cut",
"them all to pieces if",
"they show their faces",
"again, then burn the",
"rest alive upon a pyre,",
"for all to see, as a"
),
new BookPageInfo
(
"warning of Thy",
"Power. How could",
"they have gotten past",
"me? I sleep against",
"the very walls, to",
"hear Thy Words, to",
"feel Thy Breath. I",
"can find no egress"
),
new BookPageInfo
(
"from the chambers",
"that the Sewel woman",
"does not know of nor",
"have men working at",
"excavating. Where",
"have they gone,",
"Master? Have you",
"taken them, or do they"
),
new BookPageInfo
(
"truly flee from Thy",
"Presence? I will kill",
"them if they show",
"their faces again.",
"Give me Strength, my",
"Master, to let them",
"live a while longer,",
"until they have"
),
new BookPageInfo
(
"fulfilled their",
"purpose and I kneel",
"before Thee, covered",
"in their blood."
)
);
[Constructible]
public LysanderNotebook8() : base(Utility.Random(0xFF1, 2), false)
{
}
public LysanderNotebook8(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class LysanderNotebook11 : BaseBook
{
public static readonly BookContent Content = new BookContent
(
"Lysander's Notebook", "L. Gathenwale",
new BookPageInfo
(
"Day Eleven - Day",
"Thirteen:",
"",
"I come for Thee, my",
"Master. I come! The",
"way is clear, I have",
"found Thy path and",
"washed it in the blood"
),
new BookPageInfo
(
"of the two workers",
"that caught sight of",
"me. Ah, how sweet it",
"was to cut them open,",
"to see the blood pour",
"out in great torrents, to",
"stand in it, to revel in",
"it. If only I had time"
),
new BookPageInfo
(
"for the Sewel woman.",
"But there will be time",
"enough for her. I",
"have learned Thy",
"Patience, Master. I",
"come for Thee. I walk",
"Thy halls in penance,",
"my last steps in this"
),
new BookPageInfo
(
"repulsive living",
"frame. I come for",
"Thee and Thy Gifts,",
"my Master. Glory",
"Unto Thee, Khal",
"Ankur, Keeper of the",
"Seventh Death,",
"Master, Leader of the"
),
new BookPageInfo
(
"Chosen, the Khaldun.",
"Praises in Thy",
"Name, Master of Life",
"and Death, Lord of All.",
" Khal Ankur, Master,",
"Prophet, I join Thy",
"ranks this night, a",
"member of the"
),
new BookPageInfo
(
"Khaldun at last!"
)
);
[Constructible]
public LysanderNotebook11() : base(Utility.Random(0xFF1, 2), false)
{
}
public LysanderNotebook11(Serial serial) : base(serial)
{
}
public override BookContent DefaultContent => Content;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,196 @@
using System;
using System.Linq;
using Server.Items;
namespace Server.Commands
{
public class GenKhaldun
{
private static int m_Count;
public static void Initialize()
{
CommandSystem.Register("GenKhaldun", AccessLevel.Administrator, GenKhaldun_OnCommand);
}
public static bool FindMorphItem(int x, int y, int z, int inactiveItemID, int activeItemID)
{
IPooledEnumerable<Item> eable = Map.Felucca.GetItemsInRange(new Point3D(x, y, z), 0);
bool found = eable.Any(item => item is MorphItem morphItem && morphItem.Z == z &&
morphItem.InactiveItemID == inactiveItemID &&
morphItem.ActiveItemID == activeItemID);
eable.Free();
return found;
}
public static bool FindEffectController(int x, int y, int z)
{
IPooledEnumerable<Item> eable = Map.Felucca.GetItemsInRange(new Point3D(x, y, z), 0);
bool found = eable.Any(item => item is EffectController && item.Z == z);
eable.Free();
return found;
}
public static T TryCreateItem<T>(int x, int y, int z, T srcItem) where T : Item
{
IPooledEnumerable<T> eable = Map.Felucca.GetItemsInBounds<T>(new Rectangle2D(x, y, 1, 1));
T t = eable.FirstOrDefault(item => item.GetType() == srcItem.GetType());
eable.Free();
if (t != null)
{
srcItem.Delete();
return t;
}
srcItem.MoveToWorld(new Point3D(x, y, z), Map.Felucca);
m_Count++;
return srcItem;
}
public static void CreateMorphItem(int x, int y, int z, int inactiveItemID, int activeItemID, int range)
{
if (FindMorphItem(x, y, z, inactiveItemID, activeItemID))
return;
MorphItem item = new MorphItem(inactiveItemID, activeItemID, range, 3);
item.MoveToWorld(new Point3D(x, y, z), Map.Felucca);
m_Count++;
}
public static void CreateApproachLight(int x, int y, int z, int off, int on, LightType light)
{
if (FindMorphItem(x, y, z, off, on))
return;
MorphItem item = new MorphItem(off, on, 2, 3);
item.Light = light;
item.MoveToWorld(new Point3D(x, y, z), Map.Felucca);
m_Count++;
}
public static void CreateSoundEffect(int x, int y, int z, int sound, int range)
{
if (FindEffectController(x, y, z))
return;
EffectController item = new EffectController();
item.SoundID = sound;
item.TriggerType = EffectTriggerType.InRange;
item.TriggerRange = range;
item.MoveToWorld(new Point3D(x, y, z), Map.Felucca);
m_Count++;
}
public static void CreateBigTeleporterItem(int x, int y, bool reverse)
{
if (FindMorphItem(x, y, 0, reverse ? 0x17DC : 0x17EE, reverse ? 0x17EE : 0x17DC))
return;
MorphItem item = new MorphItem(reverse ? 0x17DC : 0x17EE, reverse ? 0x17EE : 0x17DC, 1, 3);
item.MoveToWorld(new Point3D(x, y, 0), Map.Felucca);
m_Count++;
}
public static void GenKhaldun_OnCommand(CommandEventArgs e)
{
m_Count = 0;
// Generate Morph Items
CreateMorphItem(5459, 1416, 0, 0x1D0, 0x1, 1);
CreateMorphItem(5460, 1416, 0, 0x1D0, 0x1, 1);
CreateMorphItem(5459, 1416, 0, 0x1, 0x53D, 1);
CreateMorphItem(5460, 1416, 0, 0x1, 0x53B, 1);
CreateMorphItem(5459, 1425, 0, 0x1, 0x53B, 2);
CreateMorphItem(5459, 1426, 0, 0x1, 0x53B, 2);
CreateMorphItem(5459, 1427, 0, 0x1, 0x53B, 2);
CreateMorphItem(5460, 1425, 0, 0x1, 0x53B, 2);
CreateMorphItem(5460, 1426, 0, 0x1, 0x53B, 2);
CreateMorphItem(5460, 1427, 0, 0x1, 0x53B, 2);
CreateMorphItem(5461, 1427, 0, 0x1, 0x53B, 2);
CreateMorphItem(5460, 1422, 0, 0x1, 0x544, 2);
CreateMorphItem(5460, 1419, 0, 0x1, 0x545, 2);
CreateMorphItem(5460, 1420, 0, 0x1, 0x545, 2);
CreateMorphItem(5460, 1423, 0, 0x1, 0x545, 2);
CreateMorphItem(5460, 1424, 0, 0x1, 0x545, 2);
CreateMorphItem(5461, 1426, 0, 0x1, 0x545, 2);
CreateMorphItem(5460, 1417, 0, 0x1, 0x546, 1);
CreateMorphItem(5460, 1418, 0, 0x1, 0x546, 2);
CreateMorphItem(5460, 1421, 0, 0x1, 0x546, 2);
CreateMorphItem(5461, 1425, 0, 0x1, 0x548, 2);
CreateMorphItem(5459, 1420, 0, 0x1, 0x54A, 2);
CreateMorphItem(5459, 1421, 0, 0x1, 0x54A, 2);
CreateMorphItem(5459, 1423, 0, 0x1, 0x54A, 2);
CreateMorphItem(5459, 1418, 0, 0x1, 0x54B, 2);
CreateMorphItem(5459, 1422, 0, 0x1, 0x54B, 2);
CreateMorphItem(5459, 1417, 0, 0x1, 0x54C, 1);
CreateMorphItem(5459, 1419, 0, 0x1, 0x54C, 2);
CreateMorphItem(5459, 1424, 0, 0x1, 0x54C, 2);
CreateMorphItem(5458, 1426, 0, 0x1, 0x1D1, 2);
CreateMorphItem(5459, 1427, 0, 0x1, 0x1E3, 2);
CreateMorphItem(5458, 1425, 3, 0x1, 0x1E4, 2);
CreateMorphItem(5458, 1427, 6, 0x1, 0x1E5, 2);
CreateMorphItem(5461, 1427, 0, 0x1, 0x1E8, 2);
CreateMorphItem(5460, 1427, 0, 0x1, 0x1E9, 2);
CreateMorphItem(5458, 1425, 0, 0x1, 0x1EA, 2);
CreateMorphItem(5458, 1427, 0, 0x1, 0x1EA, 2);
CreateMorphItem(5458, 1427, 3, 0x1, 0x1EA, 2);
// Generate Approach Lights
CreateApproachLight(5393, 1417, 0, 0x1857, 0x1858, LightType.Circle150);
CreateApproachLight(5393, 1420, 0, 0x1857, 0x1858, LightType.Circle150);
CreateApproachLight(5395, 1421, 0, 0x1857, 0x1858, LightType.Circle150);
CreateApproachLight(5396, 1417, 0, 0x1857, 0x1858, LightType.Circle150);
CreateApproachLight(5397, 1419, 0, 0x1857, 0x1858, LightType.Circle150);
CreateApproachLight(5441, 1393, 5, 0x1F2B, 0x19BB, LightType.Circle225);
CreateApproachLight(5446, 1393, 5, 0x1F2B, 0x19BB, LightType.Circle225);
// Generate Sound Effects
CreateSoundEffect(5425, 1489, 5, 0x102, 1);
CreateSoundEffect(5425, 1491, 5, 0x102, 1);
CreateSoundEffect(5449, 1499, 10, 0xF5, 1);
CreateSoundEffect(5451, 1499, 10, 0xF5, 1);
CreateSoundEffect(5453, 1499, 10, 0xF5, 1);
CreateSoundEffect(5524, 1367, 0, 0x102, 1);
CreateSoundEffect(5450, 1370, 0, 0x220, 2);
CreateSoundEffect(5450, 1372, 0, 0x220, 2);
CreateSoundEffect(5460, 1416, 0, 0x244, 2);
CreateSoundEffect(5483, 1439, 5, 0x14, 3);
// Generate Big Teleporter
CreateBigTeleporterItem(5387, 1325, true);
CreateBigTeleporterItem(5388, 1326, true);
CreateBigTeleporterItem(5388, 1325, false);
CreateBigTeleporterItem(5387, 1326, false);
// Generate Central Khaldun entrance
DisappearingRaiseSwitch sw =
TryCreateItem(5459, 1426, 10, new DisappearingRaiseSwitch());
RaiseSwitch lv = TryCreateItem(5403, 1359, 0, new RaiseSwitch());
RaisableItem stone =
TryCreateItem(5403, 1360, 0, new RaisableItem(0x788, 10, 0x477, 0x475, TimeSpan.FromMinutes(1.5)));
RaisableItem door =
TryCreateItem(5524, 1367, 0, new RaisableItem(0x1D0, 20, 0x477, 0x475, TimeSpan.FromMinutes(5.0)));
sw.RaisableItem = stone;
lv.RaisableItem = door;
e.Mobile.SendMessage($"{m_Count} dynamic Khaldun item{(m_Count == 1 ? "" : "s")} generated.");
}
}
}

View file

@ -0,0 +1,93 @@
using Server.Mobiles;
namespace Server.Items
{
public class KhaldunPitTeleporter : Item
{
[Constructible]
public KhaldunPitTeleporter() : this(new Point3D(5451, 1374, 0), Map.Felucca)
{
}
[Constructible]
public KhaldunPitTeleporter(Point3D pointDest, Map mapDest) : base(0x053B)
{
Movable = false;
Hue = 1;
Active = true;
PointDest = pointDest;
MapDest = mapDest;
}
public KhaldunPitTeleporter(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Active{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public Point3D PointDest{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public Map MapDest{ get; set; }
public override int LabelNumber =>
1016511; // the floor of the cavern seems to have collapsed here - a faint light is visible at the bottom of the pit
public override void OnDoubleClick(Mobile m)
{
if (!Active)
return;
Map map = MapDest;
if (map == null || map == Map.Internal)
map = m.Map;
Point3D p = PointDest;
if (p == Point3D.Zero)
p = m.Location;
if (m.InRange(this, 3))
{
BaseCreature.TeleportPets(m, PointDest, MapDest);
m.MoveToWorld(PointDest, MapDest);
}
else
{
m.SendLocalizedMessage(1019045); // I can't reach that.
}
}
public override void OnDoubleClickDead(Mobile m)
{
OnDoubleClick(m);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Active);
writer.Write(PointDest);
writer.Write(MapDest);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Active = reader.ReadBool();
PointDest = reader.ReadPoint3D();
MapDest = reader.ReadMap();
}
}
}

View file

@ -0,0 +1,130 @@
using Server.Items;
namespace Server.Mobiles
{
public class GrimmochDrummel : BaseCreature
{
[Constructible]
public GrimmochDrummel() : base(AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Title = "the Cursed";
Hue = 0x8596;
Body = 0x190;
HairItemID = 0x204A; //Krisna
Bow bow = new Bow();
bow.Movable = false;
AddItem(bow);
AddItem(new Boots(0x8A4));
AddItem(new BodySash(0x8A4));
Backpack backpack = new Backpack();
backpack.Movable = false;
AddItem(backpack);
LeatherGloves gloves = new LeatherGloves();
LeatherChest chest = new LeatherChest();
gloves.Hue = 0x96F;
chest.Hue = 0x96F;
AddItem(gloves);
AddItem(chest);
SetStr(111, 120);
SetDex(151, 160);
SetInt(41, 50);
SetHits(180, 207);
SetMana(0);
SetDamage(13, 16);
SetResistance(ResistanceType.Physical, 35, 45);
SetResistance(ResistanceType.Fire, 25, 30);
SetResistance(ResistanceType.Cold, 45, 55);
SetResistance(ResistanceType.Poison, 30, 40);
SetResistance(ResistanceType.Energy, 20, 25);
SetSkill(SkillName.Archery, 90.1, 110.0);
SetSkill(SkillName.Swords, 60.1, 70.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 60.1, 70.0);
SetSkill(SkillName.Anatomy, 90.1, 100.0);
Fame = 5000;
Karma = -1000;
PackItem(new Arrow(40));
if (3 > Utility.Random(100))
PackItem(new FireHorn());
if (1 > Utility.Random(3))
PackItem(Loot.RandomGrimmochJournal());
}
public GrimmochDrummel(Serial serial) : base(serial)
{
}
public override bool ClickTitle => false;
public override bool ShowFameTitle => false;
public override bool DeleteCorpseOnDeath => true;
public override string DefaultName => "Grimmoch Drummel";
public override bool AlwaysMurderer => true;
public override int GetIdleSound()
{
return 0x178;
}
public override int GetAngerSound()
{
return 0x1AC;
}
public override int GetDeathSound()
{
return 0x27E;
}
public override int GetHurtSound()
{
return 0x177;
}
public override bool OnBeforeDeath()
{
Gold gold = new Gold(Utility.RandomMinMax(190, 230));
gold.MoveToWorld(Location, Map);
Container pack = Backpack;
if (pack != null)
{
pack.Movable = true;
pack.MoveToWorld(Location, Map);
}
Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1);
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,130 @@
using Server.Items;
namespace Server.Mobiles
{
public class LysanderGathenwale : BaseCreature
{
[Constructible]
public LysanderGathenwale() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Title = "the Cursed";
Hue = 0x8838;
Body = 0x190;
AddItem(new Boots(0x599));
AddItem(new Cloak(0x96F));
Spellbook spellbook = new Spellbook();
RingmailGloves gloves = new RingmailGloves();
StuddedChest chest = new StuddedChest();
PlateArms arms = new PlateArms();
spellbook.Hue = 0x599;
gloves.Hue = 0x599;
chest.Hue = 0x96F;
arms.Hue = 0x599;
AddItem(spellbook);
AddItem(gloves);
AddItem(chest);
AddItem(arms);
SetStr(111, 120);
SetDex(71, 80);
SetInt(121, 130);
SetHits(180, 207);
SetMana(227, 265);
SetDamage(5, 13);
SetResistance(ResistanceType.Physical, 35, 45);
SetResistance(ResistanceType.Fire, 25, 30);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 25, 35);
SetResistance(ResistanceType.Energy, 25, 35);
SetSkill(SkillName.Wrestling, 80.1, 90.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 80.1, 90.0);
SetSkill(SkillName.Magery, 90.1, 100.0);
SetSkill(SkillName.EvalInt, 95.1, 100.0);
SetSkill(SkillName.Meditation, 90.1, 100.0);
Fame = 5000;
Karma = -10000;
Item reags = Loot.RandomReagent();
reags.Amount = 30;
PackItem(reags);
}
public LysanderGathenwale(Serial serial) : base(serial)
{
}
public override bool ClickTitle => false;
public override bool ShowFameTitle => false;
public override bool DeleteCorpseOnDeath => true;
public override string DefaultName => "Lysander Gatherwale";
public override bool AlwaysMurderer => true;
public override int GetIdleSound()
{
return 0x1CE;
}
public override int GetAngerSound()
{
return 0x1AC;
}
public override int GetDeathSound()
{
return 0x182;
}
public override int GetHurtSound()
{
return 0x28D;
}
public override void GenerateLoot()
{
AddLoot(LootPack.MedScrolls, 2);
}
public override bool OnBeforeDeath()
{
if (!base.OnBeforeDeath())
return false;
Backpack?.Destroy();
if (Utility.Random(3) == 0)
{
BaseBook notebook = Loot.RandomLysanderNotebook();
notebook.MoveToWorld(Location, Map);
}
Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1);
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,110 @@
using Server.Items;
namespace Server.Mobiles
{
public class MorgBergen : BaseCreature
{
[Constructible]
public MorgBergen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Title = "the Cursed";
Hue = 0x8596;
Body = 0x190;
AddItem(new ShortPants(0x59C));
Bardiche bardiche = new Bardiche();
LeatherGloves gloves = new LeatherGloves();
LeatherArms arms = new LeatherArms();
bardiche.Hue = 0x96F;
bardiche.Movable = false;
gloves.Hue = 0x96F;
arms.Hue = 0x96F;
AddItem(bardiche);
AddItem(gloves);
AddItem(arms);
SetStr(111, 120);
SetDex(111, 120);
SetInt(51, 60);
SetHits(180, 207);
SetMana(0);
SetDamage(9, 17);
SetDamageType(ResistanceType.Physical, 40);
SetDamageType(ResistanceType.Cold, 60);
SetResistance(ResistanceType.Physical, 35, 45);
SetResistance(ResistanceType.Fire, 25, 30);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 25, 35);
SetResistance(ResistanceType.Energy, 25, 35);
SetSkill(SkillName.Swords, 90.1, 100.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 80.1, 90.0);
SetSkill(SkillName.Anatomy, 90.1, 100.0);
Fame = 5000;
Karma = -1000;
}
public MorgBergen(Serial serial) : base(serial)
{
}
public override bool ShowFameTitle => false;
public override bool DeleteCorpseOnDeath => true;
public override string DefaultName => "Morg Bergen";
public override bool AlwaysMurderer => true;
public override int GetIdleSound()
{
return 0x1CE;
}
public override int GetAngerSound()
{
return 0x263;
}
public override int GetDeathSound()
{
return 0x1D1;
}
public override int GetHurtSound()
{
return 0x25E;
}
public override bool OnBeforeDeath()
{
Gold gold = new Gold(Utility.RandomMinMax(190, 230));
gold.MoveToWorld(Location, Map);
Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1);
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,120 @@
using Server.Items;
namespace Server.Mobiles
{
public class TavaraSewel : BaseCreature
{
[Constructible]
public TavaraSewel() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Title = "the Cursed";
Hue = 0x8838;
Female = true;
Body = 0x191;
AddItem(new Kilt(0x59C));
AddItem(new Sandals(0x599));
Kryss kryss = new Kryss();
Buckler buckler = new Buckler();
RingmailGloves gloves = new RingmailGloves();
FemalePlateChest chest = new FemalePlateChest();
kryss.Hue = 0x96F;
kryss.Movable = false;
buckler.Hue = 0x96F;
buckler.Movable = false;
gloves.Hue = 0x599;
chest.Hue = 0x96F;
AddItem(kryss);
AddItem(buckler);
AddItem(gloves);
AddItem(chest);
SetStr(111, 120);
SetDex(111, 120);
SetInt(111, 120);
SetHits(180, 207);
SetStam(126, 150);
SetMana(0);
SetDamage(13, 16);
SetResistance(ResistanceType.Physical, 25, 30);
SetResistance(ResistanceType.Fire, 25, 30);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 25, 35);
SetResistance(ResistanceType.Energy, 25, 35);
SetSkill(SkillName.Fencing, 90.1, 100.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 80.1, 90.0);
SetSkill(SkillName.Anatomy, 90.1, 100.0);
Fame = 5000;
Karma = -1000;
}
public TavaraSewel(Serial serial) : base(serial)
{
}
public override bool ShowFameTitle => false;
public override bool DeleteCorpseOnDeath => true;
public override string DefaultName => "Tavara Sewel";
public override bool AlwaysMurderer => true;
public override int GetIdleSound()
{
return 0x27F;
}
public override int GetAngerSound()
{
return 0x258;
}
public override int GetDeathSound()
{
return 0x25B;
}
public override int GetHurtSound()
{
return 0x257;
}
public override bool OnBeforeDeath()
{
Gold gold = new Gold(Utility.RandomMinMax(190, 230));
gold.MoveToWorld(Location, Map);
if (Utility.Random(3) == 0)
{
BaseBook journal = Loot.RandomTavarasJournal();
journal.MoveToWorld(Location, Map);
}
Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1);
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,808 @@
using System;
using System.Collections.Generic;
using Server.Gumps;
using Server.Network;
namespace Server.Items
{
public enum PuzzleChestCylinder
{
None = 0xE73,
LightBlue = 0x186F,
Blue = 0x186A,
Green = 0x186B,
Orange = 0x186C,
Purple = 0x186D,
Red = 0x186E,
DarkBlue = 0x1869,
Yellow = 0x1870
}
public class PuzzleChestSolution
{
public const int Length = 5;
public PuzzleChestSolution()
{
for (int i = 0; i < Cylinders.Length; i++) Cylinders[i] = RandomCylinder();
}
public PuzzleChestSolution(PuzzleChestCylinder first, PuzzleChestCylinder second, PuzzleChestCylinder third,
PuzzleChestCylinder fourth, PuzzleChestCylinder fifth)
{
First = first;
Second = second;
Third = third;
Fourth = fourth;
Fifth = fifth;
}
public PuzzleChestSolution(PuzzleChestSolution solution)
{
for (int i = 0; i < Cylinders.Length; i++) Cylinders[i] = solution.Cylinders[i];
}
public PuzzleChestSolution(GenericReader reader)
{
int version = reader.ReadEncodedInt();
int length = reader.ReadEncodedInt();
for (int i = 0;; i++)
if (i < length)
{
PuzzleChestCylinder cylinder = (PuzzleChestCylinder)reader.ReadInt();
if (i < Cylinders.Length)
Cylinders[i] = cylinder;
}
else if (i < Cylinders.Length)
{
Cylinders[i] = RandomCylinder();
}
else
{
break;
}
}
public PuzzleChestCylinder[] Cylinders{ get; } = new PuzzleChestCylinder[Length];
public PuzzleChestCylinder First
{
get => Cylinders[0];
set => Cylinders[0] = value;
}
public PuzzleChestCylinder Second
{
get => Cylinders[1];
set => Cylinders[1] = value;
}
public PuzzleChestCylinder Third
{
get => Cylinders[2];
set => Cylinders[2] = value;
}
public PuzzleChestCylinder Fourth
{
get => Cylinders[3];
set => Cylinders[3] = value;
}
public PuzzleChestCylinder Fifth
{
get => Cylinders[4];
set => Cylinders[4] = value;
}
public static PuzzleChestCylinder RandomCylinder()
{
switch (Utility.Random(8))
{
case 0: return PuzzleChestCylinder.LightBlue;
case 1: return PuzzleChestCylinder.Blue;
case 2: return PuzzleChestCylinder.Green;
case 3: return PuzzleChestCylinder.Orange;
case 4: return PuzzleChestCylinder.Purple;
case 5: return PuzzleChestCylinder.Red;
case 6: return PuzzleChestCylinder.DarkBlue;
default: return PuzzleChestCylinder.Yellow;
}
}
public bool Matches(PuzzleChestSolution solution, out int cylinders, out int colors)
{
cylinders = 0;
colors = 0;
bool[] matchesSrc = new bool[solution.Cylinders.Length];
bool[] matchesDst = new bool[solution.Cylinders.Length];
for (int i = 0; i < Cylinders.Length; i++)
if (Cylinders[i] == solution.Cylinders[i])
{
cylinders++;
matchesSrc[i] = true;
matchesDst[i] = true;
}
for (int i = 0; i < Cylinders.Length; i++)
if (!matchesSrc[i])
for (int j = 0; j < solution.Cylinders.Length; j++)
if (Cylinders[i] == solution.Cylinders[j] && !matchesDst[j])
{
colors++;
matchesDst[j] = true;
}
return cylinders == Cylinders.Length;
}
public virtual void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(Cylinders.Length);
for (int i = 0; i < Cylinders.Length; i++) writer.Write((int)Cylinders[i]);
}
}
public class PuzzleChestSolutionAndTime : PuzzleChestSolution
{
public PuzzleChestSolutionAndTime(DateTime when, PuzzleChestSolution solution) : base(solution)
{
When = when;
}
public PuzzleChestSolutionAndTime(GenericReader reader) : base(reader)
{
int version = reader.ReadEncodedInt();
When = reader.ReadDeltaTime();
}
public DateTime When{ get; }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.WriteDeltaTime(When);
}
}
public abstract class PuzzleChest : BaseTreasureChest
{
public const int HintsCount = 3;
public readonly TimeSpan CleanupTime = TimeSpan.FromHours(1.0);
private Dictionary<Mobile, PuzzleChestSolutionAndTime> m_Guesses =
new Dictionary<Mobile, PuzzleChestSolutionAndTime>();
private PuzzleChestSolution m_Solution;
public PuzzleChest(int itemID) : base(itemID)
{
}
public PuzzleChest(Serial serial) : base(serial)
{
}
public PuzzleChestSolution Solution
{
get => m_Solution;
set
{
m_Solution = value;
InitHints();
}
}
public PuzzleChestCylinder[] Hints{ get; private set; } = new PuzzleChestCylinder[HintsCount];
public PuzzleChestCylinder FirstHint
{
get => Hints[0];
set => Hints[0] = value;
}
public PuzzleChestCylinder SecondHint
{
get => Hints[1];
set => Hints[1] = value;
}
public PuzzleChestCylinder ThirdHint
{
get => Hints[2];
set => Hints[2] = value;
}
public override string DefaultName => null;
private void InitHints()
{
List<PuzzleChestCylinder> list = new List<PuzzleChestCylinder>(Solution.Cylinders.Length - 1);
for (int i = 1; i < Solution.Cylinders.Length; i++)
list.Add(Solution.Cylinders[i]);
Hints = new PuzzleChestCylinder[HintsCount];
for (int i = 0; i < Hints.Length; i++)
{
int pos = Utility.Random(list.Count);
Hints[i] = list[pos];
list.RemoveAt(pos);
}
}
protected override void SetLockLevel()
{
LockLevel = 0; // Can't be unlocked
}
public override bool CheckLocked(Mobile from)
{
if (Locked)
{
PuzzleChestSolution solution = GetLastGuess(from);
if (solution != null)
solution = new PuzzleChestSolution(solution);
else
solution = new PuzzleChestSolution(PuzzleChestCylinder.None, PuzzleChestCylinder.None,
PuzzleChestCylinder.None, PuzzleChestCylinder.None, PuzzleChestCylinder.None);
from.CloseGump<PuzzleGump>();
from.CloseGump<StatusGump>();
from.SendGump(new PuzzleGump(from, this, solution, 0));
return true;
}
return false;
}
public PuzzleChestSolutionAndTime GetLastGuess(Mobile m)
{
m_Guesses.TryGetValue(m, out PuzzleChestSolutionAndTime pcst);
return pcst;
}
public void SubmitSolution(Mobile m, PuzzleChestSolution solution)
{
if (solution.Matches(Solution, out int correctCylinders, out int correctColors))
{
LockPick(m);
DisplayTo(m);
}
else
{
m_Guesses[m] = new PuzzleChestSolutionAndTime(DateTime.UtcNow, solution);
m.SendGump(new StatusGump(correctCylinders, correctColors));
DoDamage(m);
}
}
public void DoDamage(Mobile to)
{
switch (Utility.Random(4))
{
case 0:
{
Effects.SendLocationEffect(to, to.Map, 0x113A, 20, 10);
to.PlaySound(0x231);
to.LocalOverheadMessage(MessageType.Regular, 0x44, 1010523); // A toxic vapor envelops thee.
to.ApplyPoison(to, Poison.Regular);
break;
}
case 1:
{
Effects.SendLocationEffect(to, to.Map, 0x3709, 30);
to.PlaySound(0x54);
to.LocalOverheadMessage(MessageType.Regular, 0xEE, 1010524); // Searing heat scorches thy skin.
AOS.Damage(to, to, Utility.RandomMinMax(10, 40), 0, 100, 0, 0, 0);
break;
}
case 2:
{
to.PlaySound(0x223);
to.LocalOverheadMessage(MessageType.Regular, 0x62,
1010525); // Pain lances through thee from a sharp metal blade.
AOS.Damage(to, to, Utility.RandomMinMax(10, 40), 100, 0, 0, 0, 0);
break;
}
default:
{
to.BoltEffect(0);
to.LocalOverheadMessage(MessageType.Regular, 0xDA, 1010526); // Lightning arcs through thy body.
AOS.Damage(to, to, Utility.RandomMinMax(10, 40), 0, 0, 0, 0, 100);
break;
}
}
}
public override void LockPick(Mobile from)
{
base.LockPick(from);
m_Guesses.Clear();
}
private static void GetRandomAOSStats(out int attributeCount, out int min, out int max)
{
int rnd = Utility.Random(15);
if (rnd < 1)
{
attributeCount = Utility.RandomMinMax(2, 6);
min = 20;
max = 70;
}
else if (rnd < 3)
{
attributeCount = Utility.RandomMinMax(2, 4);
min = 20;
max = 50;
}
else if (rnd < 6)
{
attributeCount = Utility.RandomMinMax(2, 3);
min = 20;
max = 40;
}
else if (rnd < 10)
{
attributeCount = Utility.RandomMinMax(1, 2);
min = 10;
max = 30;
}
else
{
attributeCount = 1;
min = 10;
max = 20;
}
}
protected override void GenerateTreasure()
{
DropItem(new Gold(600, 900));
List<Item> gems = new List<Item>();
for (int i = 0; i < 9; i++)
{
Item gem = Loot.RandomGem();
Type gemType = gem.GetType();
foreach (Item listGem in gems)
if (listGem.GetType() == gemType)
{
listGem.Amount++;
gem.Delete();
break;
}
if (!gem.Deleted)
gems.Add(gem);
}
foreach (Item gem in gems)
DropItem(gem);
if (0.2 > Utility.RandomDouble())
DropItem(new BagOfReagents());
for (int i = 0; i < 2; i++)
{
Item item;
if (Core.AOS)
item = Loot.RandomArmorOrShieldOrWeaponOrJewelry();
else
item = Loot.RandomArmorOrShieldOrWeapon();
if (item is BaseWeapon weapon)
{
if (Core.AOS)
{
GetRandomAOSStats(out int attributeCount, out int min, out int max);
BaseRunicTool.ApplyAttributesTo(weapon, attributeCount, min, max);
}
else
{
weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(6);
weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(6);
weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(6);
}
DropItem(weapon);
}
else if (item is BaseArmor armor)
{
if (Core.AOS)
{
GetRandomAOSStats(out int attributeCount, out int min, out int max);
BaseRunicTool.ApplyAttributesTo(armor, attributeCount, min, max);
}
else
{
armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(6);
armor.Durability = (ArmorDurabilityLevel)Utility.Random(6);
}
DropItem(armor);
}
else if (item is BaseHat hat)
{
if (Core.AOS)
{
GetRandomAOSStats(out int attributeCount, out int min, out int max);
BaseRunicTool.ApplyAttributesTo(hat, attributeCount, min, max);
}
DropItem(hat);
}
else if (item is BaseJewel jewel)
{
GetRandomAOSStats(out int attributeCount, out int min, out int max);
BaseRunicTool.ApplyAttributesTo(jewel, attributeCount, min, max);
DropItem(jewel);
}
}
Solution = new PuzzleChestSolution();
}
public void CleanupGuesses()
{
List<Mobile> toDelete = new List<Mobile>();
foreach (KeyValuePair<Mobile, PuzzleChestSolutionAndTime> kvp in m_Guesses)
if (DateTime.UtcNow - kvp.Value.When > CleanupTime)
toDelete.Add(kvp.Key);
foreach (Mobile m in toDelete)
m_Guesses.Remove(m);
}
public override void Serialize(GenericWriter writer)
{
CleanupGuesses();
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
m_Solution.Serialize(writer);
writer.WriteEncodedInt(Hints.Length);
for (int i = 0; i < Hints.Length; i++) writer.Write((int)Hints[i]);
writer.WriteEncodedInt(m_Guesses.Count);
foreach (KeyValuePair<Mobile, PuzzleChestSolutionAndTime> kvp in m_Guesses)
{
writer.Write(kvp.Key);
kvp.Value.Serialize(writer);
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
m_Solution = new PuzzleChestSolution(reader);
int length = reader.ReadEncodedInt();
for (int i = 0; i < length; i++)
{
PuzzleChestCylinder cylinder = (PuzzleChestCylinder)reader.ReadInt();
if (length == Hints.Length)
Hints[i] = cylinder;
}
if (length != Hints.Length)
InitHints();
int guesses = reader.ReadEncodedInt();
for (int i = 0; i < guesses; i++)
{
Mobile m = reader.ReadMobile();
PuzzleChestSolutionAndTime sol = new PuzzleChestSolutionAndTime(reader);
m_Guesses[m] = sol;
}
}
private class PuzzleGump : Gump
{
private PuzzleChest m_Chest;
private Mobile m_From;
private PuzzleChestSolution m_Solution;
public PuzzleGump(Mobile from, PuzzleChest chest, PuzzleChestSolution solution, int check) : base(50, 50)
{
m_From = from;
m_Chest = chest;
m_Solution = solution;
Draggable = false;
AddBackground(25, 0, 500, 410, 0x53);
AddImage(62, 20, 0x67);
AddHtmlLocalized(80, 36, 110, 70, 1018309, true); // A Puzzle Lock
/* Correctly choose the sequence of cylinders needed to open the latch. Each cylinder
* may potentially be used more than once. Beware! A false attempt could be deadly!
*/
AddHtmlLocalized(214, 26, 270, 90, 1018310, true, true);
AddLeftCylinderButton(62, 130, PuzzleChestCylinder.LightBlue, 10);
AddLeftCylinderButton(62, 180, PuzzleChestCylinder.Blue, 11);
AddLeftCylinderButton(62, 230, PuzzleChestCylinder.Green, 12);
AddLeftCylinderButton(62, 280, PuzzleChestCylinder.Orange, 13);
AddRightCylinderButton(451, 130, PuzzleChestCylinder.Purple, 14);
AddRightCylinderButton(451, 180, PuzzleChestCylinder.Red, 15);
AddRightCylinderButton(451, 230, PuzzleChestCylinder.DarkBlue, 16);
AddRightCylinderButton(451, 280, PuzzleChestCylinder.Yellow, 17);
double lockpicking = from.Skills.Lockpicking.Base;
if (lockpicking >= 60.0)
{
AddHtmlLocalized(160, 125, 230, 24, 1018308); // Lockpicking hint:
AddBackground(159, 150, 230, 95, 0x13EC);
if (lockpicking >= 80.0)
{
AddHtmlLocalized(165, 157, 200, 40, 1018312); // In the first slot:
AddCylinder(350, 165, chest.Solution.First);
AddHtmlLocalized(165, 197, 200, 40, 1018313); // Used in unknown slot:
AddCylinder(350, 200, chest.FirstHint);
if (lockpicking >= 90.0)
AddCylinder(350, 212, chest.SecondHint);
if (lockpicking >= 100.0)
AddCylinder(350, 224, chest.ThirdHint);
}
else
{
AddHtmlLocalized(165, 157, 200, 40, 1018313); // Used in unknown slot:
AddCylinder(350, 160, chest.FirstHint);
if (lockpicking >= 70.0)
AddCylinder(350, 172, chest.SecondHint);
}
}
PuzzleChestSolution lastGuess = chest.GetLastGuess(from);
if (lastGuess != null)
{
AddHtmlLocalized(127, 249, 170, 20, 1018311); // Thy previous guess:
AddBackground(290, 247, 115, 25, 0x13EC);
AddCylinder(281, 254, lastGuess.First);
AddCylinder(303, 254, lastGuess.Second);
AddCylinder(325, 254, lastGuess.Third);
AddCylinder(347, 254, lastGuess.Fourth);
AddCylinder(369, 254, lastGuess.Fifth);
}
AddPedestal(140, 270, solution.First, 0, check == 0);
AddPedestal(195, 270, solution.Second, 1, check == 1);
AddPedestal(250, 270, solution.Third, 2, check == 2);
AddPedestal(305, 270, solution.Fourth, 3, check == 3);
AddPedestal(360, 270, solution.Fifth, 4, check == 4);
AddButton(258, 370, 0xFA5, 0xFA7, 1);
}
private void AddLeftCylinderButton(int x, int y, PuzzleChestCylinder cylinder, int buttonID)
{
AddBackground(x, y, 30, 30, 0x13EC);
AddCylinder(x - 7, y + 10, cylinder);
AddButton(x + 38, y + 9, 0x13A8, 0x4B9, buttonID);
}
private void AddRightCylinderButton(int x, int y, PuzzleChestCylinder cylinder, int buttonID)
{
AddBackground(x, y, 30, 30, 0x13EC);
AddCylinder(x - 7, y + 10, cylinder);
AddButton(x - 26, y + 9, 0x13A8, 0x4B9, buttonID);
}
private void AddPedestal(int x, int y, PuzzleChestCylinder cylinder, int switchID, bool initialState)
{
AddItem(x, y, 0xB10);
AddItem(x - 23, y + 12, 0xB12);
AddItem(x + 23, y + 12, 0xB13);
AddItem(x, y + 23, 0xB11);
if (cylinder != PuzzleChestCylinder.None)
{
AddItem(x, y + 2, 0x51A);
AddCylinder(x - 1, y + 19, cylinder);
}
else
{
AddItem(x, y + 2, 0x521);
}
AddRadio(x + 7, y + 65, 0x867, 0x86A, initialState, switchID);
}
private void AddCylinder(int x, int y, PuzzleChestCylinder cylinder)
{
if (cylinder != PuzzleChestCylinder.None)
AddItem(x, y, (int)cylinder);
else
AddItem(x + 9, y, (int)cylinder);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (m_Chest.Deleted || info.ButtonID == 0 || !m_From.CheckAlive())
return;
if (m_From.AccessLevel == AccessLevel.Player &&
(m_From.Map != m_Chest.Map || !m_From.InRange(m_Chest.GetWorldLocation(), 2)))
{
m_From.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500446); // That is too far away.
return;
}
if (info.ButtonID == 1)
{
m_Chest.SubmitSolution(m_From, m_Solution);
}
else
{
if (info.Switches.Length == 0)
return;
int pedestal = info.Switches[0];
if (pedestal < 0 || pedestal >= m_Solution.Cylinders.Length)
return;
PuzzleChestCylinder cylinder;
switch (info.ButtonID)
{
case 10:
cylinder = PuzzleChestCylinder.LightBlue;
break;
case 11:
cylinder = PuzzleChestCylinder.Blue;
break;
case 12:
cylinder = PuzzleChestCylinder.Green;
break;
case 13:
cylinder = PuzzleChestCylinder.Orange;
break;
case 14:
cylinder = PuzzleChestCylinder.Purple;
break;
case 15:
cylinder = PuzzleChestCylinder.Red;
break;
case 16:
cylinder = PuzzleChestCylinder.DarkBlue;
break;
case 17:
cylinder = PuzzleChestCylinder.Yellow;
break;
default: return;
}
m_Solution.Cylinders[pedestal] = cylinder;
m_From.SendGump(new PuzzleGump(m_From, m_Chest, m_Solution, pedestal));
}
}
}
private class StatusGump : Gump
{
public StatusGump(int correctCylinders, int correctColors) : base(50, 50)
{
AddBackground(15, 250, 305, 163, 0x53);
AddBackground(28, 265, 280, 133, 0xBB8);
AddHtmlLocalized(35, 271, 270, 24, 1018314); // Thou hast failed to solve the puzzle!
AddHtmlLocalized(35, 297, 250, 24, 1018315); // Correctly placed colors:
AddLabel(285, 297, 0x44, correctCylinders.ToString());
AddHtmlLocalized(35, 323, 250, 24, 1018316); // Used colors in wrong slots:
AddLabel(285, 323, 0x44, correctColors.ToString());
AddButton(152, 369, 0xFA5, 0xFA7, 0);
}
}
}
[Flippable(0xE41, 0xE40)]
public class MetalGoldenPuzzleChest : PuzzleChest
{
[Constructible]
public MetalGoldenPuzzleChest() : base(0xE41)
{
}
public MetalGoldenPuzzleChest(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
[Flippable(0xE80, 0x9A8)]
public class StrongBoxPuzzle : PuzzleChest
{
[Constructible]
public StrongBoxPuzzle() : base(0xE80)
{
}
public StrongBoxPuzzle(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,170 @@
using System;
namespace Server.Items
{
public class RaisableItem : Item
{
private int m_Elevation;
private int m_MaxElevation;
private RaiseTimer m_RaiseTimer;
[Constructible]
public RaisableItem(int itemID) : this(itemID, 20, -1, -1, TimeSpan.FromMinutes(1.0))
{
}
[Constructible]
public RaisableItem(int itemID, int maxElevation, TimeSpan closeDelay) : this(itemID, maxElevation, -1, -1,
closeDelay)
{
}
[Constructible]
public RaisableItem(int itemID, int maxElevation, int moveSound, int stopSound, TimeSpan closeDelay) : base(itemID)
{
Movable = false;
m_MaxElevation = maxElevation;
MoveSound = moveSound;
StopSound = stopSound;
CloseDelay = closeDelay;
}
public RaisableItem(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int MaxElevation
{
get => m_MaxElevation;
set
{
if (value <= 0)
m_MaxElevation = 0;
else if (value >= 60)
m_MaxElevation = 60;
else
m_MaxElevation = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int MoveSound{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int StopSound{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan CloseDelay{ get; set; }
public bool IsRaisable => m_RaiseTimer == null;
public void Raise()
{
if (!IsRaisable)
return;
m_RaiseTimer = new RaiseTimer(this);
m_RaiseTimer.Start();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(m_MaxElevation);
writer.WriteEncodedInt(MoveSound);
writer.WriteEncodedInt(StopSound);
writer.Write(CloseDelay);
writer.WriteEncodedInt(m_Elevation);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
m_MaxElevation = reader.ReadEncodedInt();
MoveSound = reader.ReadEncodedInt();
StopSound = reader.ReadEncodedInt();
CloseDelay = reader.ReadTimeSpan();
int elevation = reader.ReadEncodedInt();
Z -= elevation;
}
private class RaiseTimer : Timer
{
private DateTime m_CloseTime;
private RaisableItem m_Item;
private int m_Step;
private bool m_Up;
public RaiseTimer(RaisableItem item) : base(TimeSpan.Zero, TimeSpan.FromSeconds(0.5))
{
m_Item = item;
m_CloseTime = DateTime.UtcNow + item.CloseDelay;
m_Up = true;
Priority = TimerPriority.TenMS;
}
protected override void OnTick()
{
if (m_Item.Deleted)
{
Stop();
return;
}
if (m_Step++ % 3 == 0)
{
if (m_Up)
{
m_Item.Z++;
if (++m_Item.m_Elevation >= m_Item.MaxElevation)
{
Stop();
if (m_Item.StopSound >= 0)
Effects.PlaySound(m_Item.Location, m_Item.Map, m_Item.StopSound);
m_Up = false;
m_Step = 0;
TimeSpan delay = m_CloseTime - DateTime.UtcNow;
DelayCall(delay > TimeSpan.Zero ? delay : TimeSpan.Zero, Start);
return;
}
}
else
{
m_Item.Z--;
if (--m_Item.m_Elevation <= 0)
{
Stop();
if (m_Item.StopSound >= 0)
Effects.PlaySound(m_Item.Location, m_Item.Map, m_Item.StopSound);
m_Item.m_RaiseTimer = null;
return;
}
}
}
if (m_Item.MoveSound >= 0)
Effects.PlaySound(m_Item.Location, m_Item.Map, m_Item.MoveSound);
}
}
}
}

View file

@ -0,0 +1,201 @@
using System;
using System.Linq;
using Server.Network;
namespace Server.Items
{
public class RaiseSwitch : Item
{
private ResetTimer m_ResetTimer;
public RaiseSwitch(int itemID = 0x1093) : base(itemID)
{
Movable = false;
}
public RaiseSwitch(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public RaisableItem RaisableItem{ get; set; }
public override void OnDoubleClick(Mobile m)
{
if (!m.InRange(this, 2))
{
m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
return;
}
if (RaisableItem?.Deleted == true)
RaisableItem = null;
Flip();
if (RaisableItem == null)
return;
if (RaisableItem.IsRaisable)
{
RaisableItem.Raise();
m.LocalOverheadMessage(MessageType.Regular, 0x5A, true,
"You hear a grinding noise echoing in the distance.");
}
else
{
m.LocalOverheadMessage(MessageType.Regular, 0x5A, true,
"You flip the switch again, but nothing happens.");
}
}
protected virtual void Flip()
{
if (ItemID != 0x1093)
{
ItemID = 0x1093;
StopResetTimer();
}
else
{
ItemID = 0x1095;
StartResetTimer(RaisableItem?.CloseDelay >= TimeSpan.Zero ? RaisableItem.CloseDelay : TimeSpan.FromMinutes(2.0));
}
Effects.PlaySound(Location, Map, 0x3E8);
}
protected void StartResetTimer(TimeSpan delay)
{
StopResetTimer();
m_ResetTimer = new ResetTimer(this, delay);
m_ResetTimer.Start();
}
protected void StopResetTimer()
{
if (m_ResetTimer != null)
{
m_ResetTimer.Stop();
m_ResetTimer = null;
}
}
protected virtual void Reset()
{
if (ItemID != 0x1093)
Flip();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.Write(RaisableItem);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
RaisableItem = (RaisableItem)reader.ReadItem();
Reset();
}
private class ResetTimer : Timer
{
private RaiseSwitch m_RaiseSwitch;
public ResetTimer(RaiseSwitch raiseSwitch, TimeSpan delay) : base(delay)
{
m_RaiseSwitch = raiseSwitch;
Priority = ComputePriority(delay);
}
protected override void OnTick()
{
if (m_RaiseSwitch.Deleted)
return;
m_RaiseSwitch.m_ResetTimer = null;
m_RaiseSwitch.Reset();
}
}
}
public class DisappearingRaiseSwitch : RaiseSwitch
{
[Constructible]
public DisappearingRaiseSwitch() : base(0x108F)
{
}
public DisappearingRaiseSwitch(Serial serial) : base(serial)
{
}
public int CurrentRange => Visible ? 3 : 2;
public override bool HandlesOnMovement => true;
protected override void Flip()
{
}
protected override void Reset()
{
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (Utility.InRange(m.Location, Location, CurrentRange) || Utility.InRange(oldLocation, Location, CurrentRange))
Refresh();
}
public override void OnMapChange()
{
if (!Deleted)
Refresh();
}
public override void OnLocationChange(Point3D oldLoc)
{
if (!Deleted)
Refresh();
}
public void Refresh()
{
Visible = GetMobilesInRange(CurrentRange).Any(mob => !mob.Hidden || mob.AccessLevel <= AccessLevel.Player);
}
public override void Serialize(GenericWriter writer)
{
if (RaisableItem?.Deleted == true)
RaisableItem = null;
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
Timer.DelayCall(TimeSpan.Zero, Refresh);
}
}
}