summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgumi <git@gumi.ca>2021-07-15 15:31:20 -0300
committerJesusaves <cpntb1@ymail.com>2021-07-15 15:31:20 -0300
commit46e20058607eb0c60bed6f1cafd24ca23908c0e4 (patch)
tree07d41073d0a43d10b81ffa50f479314e3318c890
parent6a39ff095a78976a6d8ce2e562b18f85ba3a17df (diff)
downloadserverdata-46e20058607eb0c60bed6f1cafd24ca23908c0e4.tar.gz
serverdata-46e20058607eb0c60bed6f1cafd24ca23908c0e4.tar.bz2
serverdata-46e20058607eb0c60bed6f1cafd24ca23908c0e4.tar.xz
serverdata-46e20058607eb0c60bed6f1cafd24ca23908c0e4.zip
Reintroduce the marriage system.
-rw-r--r--db/constants.conf2
-rw-r--r--npc/001-2/government_building.txt13
-rw-r--r--npc/014-1/wedding-officiator.txt255
-rw-r--r--npc/functions/marriage.txt232
-rw-r--r--npc/scripts.conf1
5 files changed, 500 insertions, 3 deletions
diff --git a/db/constants.conf b/db/constants.conf
index e9cc8271..4917dbb5 100644
--- a/db/constants.conf
+++ b/db/constants.conf
@@ -3027,6 +3027,7 @@ more than one separator can be used in a row (so 12_3___456 is illegal).
NPC181:181
NPC182:182
NPC183:183
+ NPC184:184
NPC185:185
NPC186:186
NPC187:187
@@ -3664,7 +3665,6 @@ more than one separator can be used in a row (so 12_3___456 is illegal).
SFX_UNBARRIER:10
SFX_HEAL:3
SFX_LIGHTNING:18
- MIN_MARRY_LEVEL:32
MAX_RAIN_SPELL_RADIUS:15
MAX_MAGIC_LEVEL:2
MFLAG_MADE_CONC_POTION_SHIFT:14
diff --git a/npc/001-2/government_building.txt b/npc/001-2/government_building.txt
index d4a73df0..9093db8f 100644
--- a/npc/001-2/government_building.txt
+++ b/npc/001-2/government_building.txt
@@ -142,9 +142,15 @@ S_give_rings:
goto L_No_Room_For_Rings;
Zeny = Zeny - WEDDING_FEE;
- getitem "WeddingRing", 1;
- getitem "WeddingRing", 1;
+ getitem WeddingRing, 1;
+ getitem WeddingRing, 1;
return;
+
+OnInit:
+ .realName$ = "Estard";
+ .distance = 5;
+ .officiator = false;
+ end;
}
001-2,22,21,0 script Guard#govt_in NPC123,{
@@ -152,3 +158,6 @@ S_give_rings:
mes "\"You're not allowed back here.\"";
close;
}
+
+001-2,21,27,0 duplicate(marriage) #handler#001-2#1 NPC_HIDDEN
+
diff --git a/npc/014-1/wedding-officiator.txt b/npc/014-1/wedding-officiator.txt
index 2c0ac5e2..ac3a6e47 100644
--- a/npc/014-1/wedding-officiator.txt
+++ b/npc/014-1/wedding-officiator.txt
@@ -7,8 +7,13 @@
goto L_Main;
L_Main:
+ if (PARTNER)
+ goto L_Main_married;
+
menu
"What exactly do you do?", L_explain_self,
+ "How do I get married?", L_explain_marriage,
+ "I would like to get married.", L_Get_married,
"Goodbye.", L_End;
L_explain_self:
@@ -20,7 +25,257 @@ L_explain_self:
next;
goto L_Main;
+L_explain_marriage:
+ mes "[Wedding Officiator]";
+ mes "\"If you are sure that you are ready to get married, then first you come and talk to me here – I need to register you, after all. You will first have to pay me a small fee of " + WEDDING_FEE + " GP.\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "\"Both you and your partner must be at least " + WEDDING_MIN_LEVEL + " levels of age, though; the law is very firm on that. But if all of that works out, I will give you two wedding rings for the ceremony.\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "\"To complete the marriage, each of you has to put on one of these rings, and you have to stand next to each other in the southern part of this park. Then one of you says `marry' and then the other person's name.\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "\"So if you would want to marry me, for example, you would say `marry Wendy'. Just like that. Your partner then has to decide whether he or she wants that. And if you both agree, then you're married!\"";
+ mes "She again smiles that broad smile of hers.";
+ next;
+ goto L_Main;
+
+L_Get_married:
+ if (Zeny < WEDDING_FEE)
+ goto L_too_poor;
+ if (BaseLevel < WEDDING_MIN_LEVEL)
+ goto L_too_young;
+
+ mes "[Wedding Officiator]";
+ mes "Wendy's eyes are sparkling.";
+ mes "\"Wow. So you and your sweetheart are ready to take the big step, then?\"";
+ next;
+ menu
+ "Yes, we are ready.", L_Next,
+ "On second thought, perhaps not.", L_End;
+
+L_Next:
+ mes "[Wedding Officiator]";
+ mes "She bounces.";
+ mes "\"That's so sweet! You must really love each other, then...?\"";
+ next;
+ menu
+ "We certainly do.", L_Next1,
+ "Yes, of course.", L_Next1,
+ "Please get on with it.", L_Next1,
+ "Hmm. Let me think about this some more.", L_End;
+
+L_Next1:
+ mes "[Wedding Officiator]";
+ mes "Wendy blushes.";
+ mes "\"Sorry if I am asking so many questions, but I have to make sure, you see... rules and all. Where were we...\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "She composes herself again.";
+ mes "\"OK. Now, what vows you exchange precisely is your choice. But a marriage is really something that is meant to last. So please take a moment to think.\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "\"Is your partner really someone you are serious about, someone you want to be with even when things get nasty, someone whom you will stick your head out for no matter how bad things get?";
+ mes "And do both of you feel that you could spend the rest of your time in this mana world together?\"";
+ next;
+ menu
+ "Yes.", L_Next2,
+ "YES.", L_Next2,
+ "Absolutely.", L_Next2,
+ "Yes. We love each other.", L_Next2,
+ "This is taking too long.", L_End,
+ "No.", L_End;
+
+L_Next2:
+ if (Zeny < WEDDING_FEE)
+ goto L_too_poor;
+ if (BaseLevel < WEDDING_MIN_LEVEL)
+ goto L_too_young;
+ getinventorylist;
+ if (@inventorylist_count > 98)
+ goto L_No_Room_For_Rings;
+
+ Zeny = Zeny - WEDDING_FEE;
+ getitem "WeddingRing", 1;
+ getitem "WeddingRing", 1;
+
+ mes "[Wedding Officiator]";
+ mes "Wendy collects the fee.";
+ mes "\"Okay... here are your wedding rings. Each of you has to have one. Put them on, stand next to each other in the southern part of this park and say `marry ...' and the name of your partner.";
+ mes "So your partner might just say `marry " + strcharinfo(0) + "' to marry you.\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "Wendy hesitates, then gives you a quick hug. There are tears are in her eyes.";
+ mes "\"Sorry, I always get a bit... emotional, I think... but I'm so happy for you!\"";
+ mes "She smiles and wipes the tears from her eyes.";
+ next;
+ mes "[Wedding Officiator]";
+ mes "\"So... I wish you the very, very best, a wonderful and happy and successful marriage!\"";
+ mes "She smiles at you again.";
+ close;
+
L_End:
close;
+L_too_young:
+ mes "[Wedding Officiator]";
+ mes "Wendy looks at her notes, shaking her head; pain is evident in her eyes.";
+ mes "\"I'm really, really sorry – I wish I could allow that, but you are still too young. You have to be at least " + WEDDING_MIN_LEVEL + " levels of age.\"";
+ close;
+
+L_too_poor:
+ mes "[Wedding Officiator]";
+ mes "\"Oh, this is so sad... you want to get married but don't have the money!\"";
+ mes "Wendy is visibly unhappy.";
+ mes "\"I wish I could help you, but the rules... you see... Well, I'm afraid that you will just have to come back when you have " + WEDDING_FEE + " GP.\"";
+ close;
+
+L_Main_married:
+ mes "[Wedding Officiator]";
+ mes "\"I hope that you and your partner are doing well?\"";
+ next;
+ menu
+ "We are very happy, thanks for asking!", L_Farewell2,
+ "Actually, things aren't so good...", L_talk_divorce;
+
+L_Farewell2:
+ mes "[Wedding Officiator]";
+ mes "Wendy is beaming.";
+ mes "\"That's wonderful! Please do say `hi' to your spouse from me!\"";
+ close;
+
+L_talk_divorce:
+ mes "[Wedding Officiator]";
+ mes "\"Oh... I am sorry to hear that. What's the problem, then?\"";
+ next;
+ menu
+ "We don't love each other anymore.", L_Nolove,
+ "My partner loves someone else.", L_partner_otherlove,
+ "I think I love someone else.", L_self_otherlove,
+ "We can't agree on who carries the loot.", L_loot;
+
+L_Nolove:
+ mes "[Wedding Officiator]";
+ mes "Wendy sighs.";
+ mes "\"I am really sorry to hear that. Have you tried talking to your partner? Tried some new dungeons? Solved some quests together?\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "\"I mean... I am sure that you have many things in common that you are not aware of. If you just do something new, perhaps you will learn something about each other that you will like?\"";
+ next;
+ menu
+ "We tried that, it didn't work.", L_makesure_divorce,
+ "Perhaps we should give it another try.", L_End;
+
+L_partner_otherlove:
+ mes "[Wedding Officiator]";
+ mes "Wendy frowns.";
+ mes "\"Are you really sure? Perhaps that other person is just a friend, or even if it isn't, perhaps it was just a small mistake on your partner's side... nobody is perfect, after all!\"";
+ next;
+ menu
+ "I'm sure. I want a divorce.", L_makesure_divorce,
+ "Perhaps we should discuss this some more first.", L_End;
+
+L_self_otherlove:
+ mes "[Wedding Officiator]";
+ mes "Wendy sighs.";
+ mes "\"Oh dear... well, I suppose that happens. You don't have any children, I think, but still, you made a promise to your partner.\"";
+ next;
+ mes "[Wedding Officiator]";
+ mes "\"Are you really sure that you love the new person so much that you want to leave your partner? Perhaps it would be good to take some time off first to make sure that you are not making a mistake here.\"";
+ next;
+ menu
+ "I'm sure. I want a divorce.", L_makesure_divorce,
+ "Let me think about this more.", L_End;
+
+L_loot:
+ mes "[Wedding Officiator]";
+ mes "Wendy blinks.";
+ mes "\"Err... have you thought about just splitting it up?\"";
+ next;
+ menu
+ "No way. I want a divorce.", L_makesure_divorce,
+ "Oh... oh! But of course!", L_End;
+
+L_makesure_divorce:
+ @divorce_cost = DIVORCE_FEE_PER_LEVEL * BaseLevel;
+
+ mes "[Wedding Officiator]";
+ mes "Resigned, Wendy looks down at her notes.";
+ mes "\"Okay. I suppose that if you are sure, I will get your divorce underway. But that will cost you " + @divorce_cost + " in administrative fees.\"";
+ next;
+ menu
+ "Let me think about this again.", L_End,
+ "HOW much? Never mind, then.", L_End,
+ "That's OK. I want the divorce.", L_do_divorce;
+
+L_divorce_nomoney:
+ mes "[Wedding Officiator]";
+ mes "\"I am sorry, but you can't seem to afford the " + @divorce_cost + " GP for a divorce at this time. Please come back later.\"";
+ close;
+
+L_do_divorce:
+ if (Zeny < @divorce_cost)
+ goto L_divorce_nomoney;
+ if (getpartnerid() && divorce() && getpartnerid() == false)
+ goto L_DidDivorce;
+
+ mes "[Wedding Officiator]";
+ mes "The officiator searches through her records for your partner.";
+ mes "\"I can't find your partner's record, you'll have to come back later.\"";
+ next;
+ mes "[Server]";
+ mes "Try again when your partner is online too.";
+ close;
+
+L_DidDivorce:
+ Zeny = Zeny - @divorce_cost;
+
+ mes "[Wedding Officiator]";
+ mes "After collecting her fee, Wendy licks her quill and writes down some notes.";
+ mes "Then she sighs heavily.";
+ mes "\"You are divorced now. Thank you for your business.\"";
+ close;
+
+L_No_Room_For_Rings:
+ mes "[Wedding Officiator]";
+ mes "\"You don't have room to carry the rings.\"";
+ close;
+
+OnDoMarriage:
+ // at this point all conditions are already checked, except the rings
+ .@target = getcharid(CHAR_ID_ACCOUNT, @marriage$);
+
+ if (!isequipped(WeddingRing)) {
+ unittalk(.id, l("You must have a %s equipped.", getitemlink(WeddingRing)), true, SELF, playerattached());
+ end;
+ }
+
+ .@prev_rid = playerattached();
+ attachrid(.@target);
+ if (!isequipped(WeddingRing)) {
+ unittalk(.id, l("You must have a %s equipped.", getitemlink(WeddingRing)), true, SELF, .@target);
+ end;
+ }
+ attachrid(.@prev_rid);
+
+ marriage(@marriage$);
+ announce(sprintf("%s and %s are now married!", strcharinfo(PC_NAME), @marriage$), bc_all);
+ npctalk("Congratulations!");
+ emotion(E_JOY); // on officiator
+ emotion(E_HEART, true, strcharinfo(PC_NAME)); // on player
+ emotion(E_HEART, true, @marriage$); // on player
+ end;
+
+
+OnInit:
+ .realName$ = "Wendy";
+ .distance = 5;
+ .officiator = true;
+ end;
}
+
+
+// Marriage core
+014-1,31,38,0 duplicate(marriage) #handler#014-1#2 NPC_HIDDEN
+
diff --git a/npc/functions/marriage.txt b/npc/functions/marriage.txt
new file mode 100644
index 00000000..d6d76aaf
--- /dev/null
+++ b/npc/functions/marriage.txt
@@ -0,0 +1,232 @@
+// marriage npc
+// allows to marry other players
+// * must be duplicated
+
+- script marriage NPC_NO_SPRITE,{
+ end;
+
+ function toPlayer {
+ // send a message to the player
+ .previous = playerattached();
+ // attachrid is required because we want to use l() on another player
+ attachrid(getarg(1, getcharid(CHAR_ID_ACCOUNT)));
+ dispbottom(b(l(getarg(0))));
+ attachrid(.previous);
+ return;
+ }
+
+ function _officiator {
+ // make the wedding officiator say a message
+ if (getarg(1, 0)) {
+ // only send to the target player
+ unittalk(.officiator, l(getarg(0)), true, SELF, getarg(1, getcharid(CHAR_ID_ACCOUNT)));
+ } else {
+ // regular npctalk
+ unittalk(.officiator, getarg(0), true);
+ }
+ return;
+ }
+
+ function officiator {
+ if (.officiator) {
+ return _officiator(getarg(0));
+ } else {
+ toPlayer(getarg(0));
+
+ if (getarg(1, 0)) {
+ toPlayer(getarg(0), getarg(1));
+ }
+ return;
+ }
+ }
+
+ function explain {
+ // send an explanation message
+ if (.officiator) {
+ return _officiator(getarg(0), playerattached());
+ } else {
+ return toPlayer(getarg(0));
+ }
+ }
+
+ function do_marriage {
+ if (.officiator) {
+ // let the officiator handle it
+ @marriage$ = getarg(0);
+ doevent(.officiator$ + "::OnDoMarriage");
+ } else {
+ // no officiator
+ marriage(getarg(0));
+ announce(sprintf("%s and %s are now married!", strcharinfo(PC_NAME), getarg(0)), bc_all);
+ }
+ return;
+ }
+
+OnCheckWord:
+ .@verb$ = strtolower($@p1$);
+ if (.@verb$ != "marry" && .@verb$ != l("marry")) {
+ end; // ignore
+ }
+
+ // get the location of the invoking character
+ getmapxy(.@map$, .@x, .@y, UNITTYPE_PC);
+
+
+ if (.@map$ != .map$ || .@x < .x1 || .@x > .x2 || .@y < .y1 || .@y > .y2) {
+ explain("You must stand in the designated area");
+ end;
+ }
+
+ // check if the target character exists and is online
+ .@target$ = $@p2$;
+ .@target = getcharid(CHAR_ID_ACCOUNT, .@target$);
+
+ if (.@target == 0) {
+ explain(sprintf("Player %s doesn't exist or is offline", .@target$));
+ end;
+ }
+
+ if (.@target == playerattached()) {
+ explain("You cannot marry yourself");
+ end;
+ }
+
+ // get the location of the target character
+ getmapxy(.@map$, .@x, .@y, UNITTYPE_PC, .@target);
+
+ if (.@map$ != .map$ || .@x < .x1 || .@x > .x2 || .@y < .y1 || .@y > .y2) {
+ explain("Your partner must stand in the designated area");
+ end;
+ }
+
+ if (BaseLevel < WEDDING_MIN_LEVEL || readparam(BaseLevel, .@target) < WEDDING_MIN_LEVEL) {
+ explain(sprintf("You and your partner must be at least level %i to marry", WEDDING_MIN_LEVEL));
+ end;
+ }
+
+ // XXX: do we want to check for wedding rings?
+ if (!isequipped(WeddingRing)) {
+ explain("You must be wearing a %s to marry.", getitemname(WeddingRing));
+ end;
+ }
+
+ if (getpartnerid()) {
+ if (getpartnerid() == getcharid(CHAR_ID_CHAR, .@target$)) {
+ explain("You are already married to this person.");
+ } else {
+ explain("You are already married to someone else.");
+ }
+ end;
+ }
+
+ if (getvariableofpc(@marriage, .@target, 0) == getcharid(CHAR_ID_CHAR)) {
+ // the target already requested to marry us
+
+ if (getvariableofpc(@marriage[1], .@target, 0) > now()) {
+ // You must be wearing a wedding ring at all times
+ if (!isequipped(WeddingRing)) {
+ explain("You must be wearing a %s to marry.", getitemname(WeddingRing));
+ end;
+ }
+ // marriage request has not expired: procceed to marry
+ do_marriage(.@target$);
+ end;
+ } else {
+ // marriage request expired
+ explain("This marriage proposal has expired. Please try again");
+
+ // refresh our own expiration
+ @marriage = getcharid(CHAR_ID_CHAR, .@target$);
+ @marriage[1] = time_from_minutes(+15); // expiration
+ }
+ } else if (@marriage && @marriage[1] > now()) {
+ // we already initiated a marriage request
+
+ if (@marriage == getcharid(CHAR_ID_CHAR, .@target$)) {
+ explain("You are already marrying this person.");
+ @marriage[1] = time_from_minutes(+15); // refresh expiration
+ } else {
+ // already marrying someone else?
+ explain("You are already in the process of marrying someone else.");
+ explain(sprintf("Are you sure you wish to marry %s?", .@target$));
+ explain(sprintf("To confirm, type the same message again: %s %s", $@p1$, $@p2$));
+ @marriage = 0; // clear the current target
+ }
+ } else {
+ // initiate a new marriage request
+ @marriage = getcharid(CHAR_ID_CHAR, .@target$);
+ @marriage[1] = time_from_minutes(+15); // expiration
+
+ announce(sprintf("%s is asking %s for marriage!", strcharinfo(PC_NAME), .@target$), bc_all);
+ officiator(sprintf("%s, to accept this marriage proposal, say: marry %s", .@target$, strcharinfo(PC_NAME)), .@target);
+ }
+ end;
+
+OnInit:
+ if (strnpcinfo(NPC_MAP) == "") {
+ // this is not a duplicate
+ end;
+ }
+
+ explode(.@hidden$, strnpcinfo(NPC_NAME_HIDDEN), "#");
+ explode(.@area$, .@hidden$[getarraysize(.@hidden$) - 1], ",");
+
+ switch (getarraysize(.@area$)) {
+ case 1:
+ if (.@area$[0] == "") {
+ .@d = 3;
+ } else {
+ .@d = atoi(.@area$[0]);
+ }
+ .x1 = .x - .@d; .x2 = .x + .@d;
+ .y1 = .y - .@d; .y2 = .y + .@d;
+ break;
+ case 2:
+ .@dx = atoi(.@area$[0]); .@dy = atoi(.@area$[1]);
+ .x1 = .x - .@dx; .x2 = .x + .@dx;
+ .y1 = .y - .@dy; .y2 = .y + .@dy;
+ break;
+ case 4:
+ .x1 = atoi(.@area$[0]); .x2 = atoi(.@area$[2]);
+ .y1 = atoi(.@area$[1]); .y2 = atoi(.@area$[3]);
+ break;
+ default:
+ consolemes(CONSOLEMES_ERROR, "unexpected number of arguments for the marriage duplicate");
+ break;
+ }
+
+ // now find the wedding officiator (if any)
+ .@count = getunits(BL_NPC, .@units, false, strnpcinfo(NPC_MAP));
+
+ freeloop(true);
+ for (.@i = 0; .@i < .@count; ++.@i) {
+ .@name$ = strtolower(strnpcinfo(NPC_NAME_HIDDEN, "", .@units[.@i]));
+ .@full$ = strnpcinfo(NPC_NAME, "", .@units[.@i]);
+
+ if (getnpcsubtype(.@units[.@i]) != NPCSUBTYPE_SCRIPT) {
+ // getunits() doesn't filter npc subtypes
+ continue;
+ }
+
+ if (endswith(.@name$, "officiator") ||
+ endswith(.@name$, "marriage") ||
+ endswith(.@name$, "wedding") ||
+ getvariableofnpc(.officiator, .@full$) ||
+ getvariableofnpc(.marriage, .@full$) ||
+ getvariableofnpc(.wedding, .@full$)) {
+ .officiator = .@units[.@i];
+ .officiator$ = .@full$;
+ break;
+ }
+ }
+ freeloop(false);
+
+ defpattern(.id, "^.+ : (?:##[0-9aBb])?([A-Za-z]+) (.{4,23})$", "OnCheckWord");
+ activatepset(.id);
+ .distance = 14;
+ end;
+}
+
+// to use, create a duplicate:
+//001-1,30,31,0 duplicate(marriage) name#x1,y1,x2,y2 NPCID
+//001-1,30,31,0 duplicate(marriage) name#range NPCID
diff --git a/npc/scripts.conf b/npc/scripts.conf
index fa3407b1..ee4481cd 100644
--- a/npc/scripts.conf
+++ b/npc/scripts.conf
@@ -54,6 +54,7 @@
"npc/functions/ghost.txt",
"npc/functions/location.txt",
"npc/functions/weather.txt",
+"npc/functions/marriage.txt",
// Items
"npc/items/purification_potion.txt",