// TMW2 Script // Author: // Jesusalva // Description: // Central Town Political System Controller // Note: The office is NOT Mayor, we have from kings to mayors here and you're // not a citzen (yet). It'll be... I'll think in a name better than Minister. // Perhaps, Town Administrator. // Variables: // $LOC_MAYOR$ - Stores the name of current Hurnscald Mayor // $LOC_MONEY - Total money reserves of Hurnscald // $LOC_TAX - How much in % is charged as taxes. (OnBuy income) // $LOC_EXPORT - Defines how much Hurnscald exports (weekly income) // $LOC_REPUTATION - Town reputation. Affects Max Tax and Weekly Income; // Note: Tax cannot exceed 10% ie 1000. Reputation must be between 0 and 100. // // "Temporary Arrays": // $LOC_CANDIDATE$ - Candidate for Office // $LOC_VOTES - Number of votes of Candidate // Proccess Taxes from purchases // PurchaseTaxes( Location ) function script PurchaseTaxes { .@tax=0; for (.@i=0; .@i < getarraysize(@bought_nameid); .@i++) { // Note: Some NPC might not .@price=getiteminfo(@bought_nameid[.@i], ITEMINFO_BUYPRICE); .@tax+=.@price*@bought_quantity[.@i]; } .@loc$=strtoupper(getarg(0, LOCATION$)); .@vat=getd("$"+.@loc$+"_TAX"); .@tax=.@tax*.@vat/10000; if (.@tax) { debugmes "%s paid %d in taxes to %s prefecture!", strcharinfo(0), .@tax, .@loc$; .@gp=getd("$"+.@loc$+"_MONEY"); setd("$"+.@loc$+"_MONEY", .@gp+.@tax); .@tp=POL_LocToTP(.@loc$); if (#EXILED & .@tp) Zeny=max(0, Zeny-.@tax); } return; } // Proccess Taxes from sales (20% from purchase tax) // SaleTaxes( Location ) function script SaleTaxes { .@tax=0; for (.@i=0; .@i < getarraysize(@sold_nameid); .@i++) { // Note: Some NPC might not .@price=getiteminfo(@sold_nameid[.@i], ITEMINFO_SELLPRICE); .@tax+=.@price*@sold_quantity[.@i]; } .@loc$=strtoupper(getarg(0, LOCATION$)); .@vat=getd("$"+.@loc$+"_TAX"); .@vat=.@vat*3/4; // Only 75% of purchase tax (defaults to 0.75% I guess) .@tax=.@tax*.@vat/10000; if (.@tax) { debugmes "Sale: %s paid %d in taxes to %s prefecture!", strcharinfo(0), .@tax, .@loc$; .@gp=getd("$"+.@loc$+"_MONEY"); setd("$"+.@loc$+"_MONEY", .@gp+.@tax); dispbottom col(l("%s is happy because you've paid %d GP in taxes!", getd("$"+.@loc$+"_MAYOR$"), .@tax), 1); Zeny-=.@tax; // Player must pay the taxes .@tp=POL_LocToTP(.@loc$); /* if (#EXILED & .@tp) Zeny=max(0, Zeny-.@tax); */ } return; } // Adjusts prices for crafts // POL_AdjustPrice( price, {TOWNCODE} ) function script POL_AdjustPrice { .@p=getarg(0); .@l$=strtoupper(getarg(1, LOCATION$)); // Town Admin is always tax exempt if (getd("$" + .@l$ + "_MAYOR$") == strcharinfo(0)) .@p=0; // Town option for tax immunity if (getd("$" + .@l$ + "_TAXOFF")) { .@vat=getd("$"+.@l$+"_TAX"); .@tax=.@p*.@vat/10000; .@p-=.@tax; } // Return adjusted price return .@p; } // Change a town money at player expense // POL_PlayerMoney( price, {TOWNCODE} ) function script POL_PlayerMoney { .@p=getarg(0); .@l$=strtoupper(getarg(1, LOCATION$)); .@t=POL_LocToTP(.@l$); Zeny-=.@p; // Town option for tax immunity if (getd("$" + .@l$ + "_TAXOFF")) { return 0; } // Calculate tax and add to town vault .@vat=getd("$"+.@l$+"_TAX"); .@tax=.@p*.@vat/10000; .@GP=getd("$" + .@l$ + "_MONEY"); if (playerattached()) { if (is_gm()) dispbottom l("GP: %d + %d", .@GP, .@tax); } setd("$" + .@l$ + "_MONEY", .@GP+.@tax); // Return the taxes paid return .@tax; } - script Politics NPC_HIDDEN,{ // Daily Paperwork Penalty OnClock2359: if ($TULIM_DAILYQUEST != gettimeparam(GETTIME_DAYOFMONTH) && $TULIM_MAYOR$ != "Jesus Saves") $TULIM_REPUTATION=limit(0, $TULIM_REPUTATION-2, 100); if ($HALIN_DAILYQUEST != gettimeparam(GETTIME_DAYOFMONTH) && $HALIN_MAYOR$ != "Jesus Saves") $HALIN_REPUTATION=limit(0, $HALIN_REPUTATION-2, 100); if ($HURNS_DAILYQUEST != gettimeparam(GETTIME_DAYOFMONTH) && $HURNS_MAYOR$ != "Jesus Saves") $HURNS_REPUTATION=limit(0, $HURNS_REPUTATION-2, 100); if ($NIVAL_DAILYQUEST != gettimeparam(GETTIME_DAYOFMONTH) && $NIVAL_MAYOR$ != "Jesus Saves") $NIVAL_REPUTATION=limit(0, $NIVAL_REPUTATION-2, 100); if ($LOF_DAILYQUEST != gettimeparam(GETTIME_DAYOFMONTH) && $LOF_MAYOR$ != "Jesus Saves") $LOF_REPUTATION=limit(0, $LOF_REPUTATION-2, 100); if ($FROSTIA_DAILYQUEST != gettimeparam(GETTIME_DAYOFMONTH) && $FROSTIA_MAYOR$ != "Jesus Saves") $FROSTIA_REPUTATION=limit(0, $FROSTIA_REPUTATION-2, 100); if ($CANDOR_DAILYQUEST != gettimeparam(GETTIME_DAYOFMONTH) && $CANDOR_MAYOR$ != "Jesus Saves") $CANDOR_REPUTATION=limit(0, $CANDOR_REPUTATION-2, 100); end; OnSun0000: // Weekly income (TODO: Use tax as reference, not reputation) $TULIM_MONEY+=$TULIM_EXPORT*limit(10, $TULIM_REPUTATION, 100)/100; $HALIN_MONEY+=$HALIN_EXPORT*limit(10, $HALIN_REPUTATION, 100)/100; $HURNS_MONEY+=$HURNS_EXPORT*limit(10, $HURNS_REPUTATION, 100)/100; $LOF_MONEY+=$LOF_EXPORT*limit(10, $LOF_REPUTATION, 100)/100; $NIVAL_MONEY+=$NIVAL_EXPORT*limit(10, $NIVAL_REPUTATION, 100)/100; $FROSTIA_MONEY+=$FROSTIA_EXPORT*limit(10, $FROSTIA_REPUTATION, 100)/100; $CANDOR_MONEY+=$CANDOR_EXPORT*limit(10, $CANDOR_REPUTATION, 100)/100; // Send salary to Town Administrators (20% from exports and 5GP/reputation) // Strange Coins: TODO .@tax=$TULIM_EXPORT*limit(0, $TULIM_REPUTATION, 100)/500; .@tax+=$TULIM_REPUTATION*5; .@tax=min($TULIM_MONEY, .@tax); $TULIM_MONEY-=.@tax; rodex_sendmail(gf_charnameid($TULIM_MAYOR$), "Tulimshar Townhall", "Term Income", "You've received the money for the term.", .@tax); .@tax=$HALIN_EXPORT*limit(0, $HALIN_REPUTATION, 100)/500; .@tax+=$HALIN_REPUTATION*5; .@tax=min($HALIN_MONEY, .@tax); $HALIN_MONEY-=.@tax; rodex_sendmail(gf_charnameid($HALIN_MAYOR$), "Halinarzo Townhall", "Term Income", "You've received the money for the term.", .@tax); .@tax=$HURNS_EXPORT*limit(0, $HURNS_REPUTATION, 100)/500; .@tax+=$HURNS_REPUTATION*5; .@tax=min($HURNS_MONEY, .@tax); $HURNS_MONEY-=.@tax; rodex_sendmail(gf_charnameid($HURNS_MAYOR$), "Hurnscald Townhall", "Term Income", "You've received the money for the term.", .@tax); .@tax=$LOF_EXPORT*limit(0, $LOF_REPUTATION, 100)/500; .@tax+=$LOF_REPUTATION*5; .@tax=min($LOF_MONEY, .@tax); $LOF_MONEY-=.@tax; rodex_sendmail(gf_charnameid($LOF_MAYOR$), "LoF Townhall", "Term Income", "You've received the money for the term.", .@tax); .@tax=$NIVAL_EXPORT*limit(0, $NIVAL_REPUTATION, 100)/500; .@tax+=$NIVAL_REPUTATION*5; .@tax=min($NIVAL_MONEY, .@tax); $NIVAL_MONEY-=.@tax; rodex_sendmail(gf_charnameid($NIVAL_MAYOR$), "Nivalis Townhall", "Term Income", "You've received the money for the term.", .@tax); /* Towns with volunteer town admins .@tax=$FROSTIA_EXPORT*limit(0, $FROSTIA_REPUTATION, 100)/500; .@tax+=$FROSTIA_REPUTATION*5; .@tax=min($FROSTIA_MONEY, .@tax); $FROSTIA_MONEY-=.@tax; rodex_sendmail(gf_charnameid($FROSTIA_MAYOR$), "Frostia Townhall", "Term Income", "You've received the money for the term.", .@tax); .@tax=$CANDOR_EXPORT*limit(0, $CANDOR_REPUTATION, 100)/500; .@tax+=$CANDOR_REPUTATION*5; .@tax=min($CANDOR_MONEY, .@tax); $CANDOR_MONEY-=.@tax; rodex_sendmail(gf_charnameid($CANDOR_MAYOR$), "Candor Townhall", "Term Income", "You've received the money for the term.", .@tax); */ // Conduct elections .@w=array_highest($TULIM_VOTES); if ($TULIM_CANDIDATE$[.@w] != "") $TULIM_MAYOR$=$TULIM_CANDIDATE$[.@w]; deletearray($TULIM_CANDIDATE$); deletearray($TULIM_VOTES); array_push($TULIM_CANDIDATE$, ($TULIM_REPUTATION < 15 ? "Jesus Saves" : $TULIM_MAYOR$)); array_push($TULIM_VOTES, 0); .@w=array_highest($HALIN_VOTES); if ($HALIN_CANDIDATE$[.@w] != "") $HALIN_MAYOR$=$HALIN_CANDIDATE$[.@w]; deletearray($HALIN_CANDIDATE$); deletearray($HALIN_VOTES); array_push($HALIN_CANDIDATE$, ($HALIN_REPUTATION < 15 ? "Jesus Saves" : $HALIN_MAYOR$)); array_push($HALIN_VOTES, 0); .@w=array_highest($HURNS_VOTES); if ($HURNS_CANDIDATE$[.@w] != "") $HURNS_MAYOR$=$HURNS_CANDIDATE$[.@w]; deletearray($HURNS_CANDIDATE$); deletearray($HURNS_VOTES); array_push($HURNS_CANDIDATE$, ($HURNS_REPUTATION < 15 ? "Jesus Saves" : $HURNS_MAYOR$)); array_push($HURNS_VOTES, 0); .@w=array_highest($LOF_VOTES); if ($LOF_CANDIDATE$[.@w] != "") $LOF_MAYOR$=$LOF_CANDIDATE$[.@w]; deletearray($LOF_CANDIDATE$); deletearray($LOF_VOTES); array_push($LOF_CANDIDATE$, ($LOF_REPUTATION < 15 ? "Jesus Saves" : $LOF_MAYOR$)); array_push($LOF_VOTES, 0); .@w=array_highest($NIVAL_VOTES); if ($NIVAL_CANDIDATE$[.@w] != "") $NIVAL_MAYOR$=$NIVAL_CANDIDATE$[.@w]; deletearray($NIVAL_CANDIDATE$); deletearray($NIVAL_VOTES); array_push($NIVAL_CANDIDATE$, ($NIVAL_REPUTATION < 15 ? "Jesus Saves" : $NIVAL_MAYOR$)); array_push($NIVAL_VOTES, 0); .@w=array_highest($FROSTIA_VOTES); if ($FROSTIA_CANDIDATE$[.@w] != "") $FROSTIA_MAYOR$=$FROSTIA_CANDIDATE$[.@w]; deletearray($FROSTIA_CANDIDATE$); deletearray($FROSTIA_VOTES); array_push($FROSTIA_CANDIDATE$, ($FROSTIA_REPUTATION < 15 ? "Jesus Saves" : $FROSTIA_MAYOR$)); array_push($FROSTIA_VOTES, 0); .@w=array_highest($CANDOR_VOTES); if ($CANDOR_CANDIDATE$[.@w] != "") $CANDOR_MAYOR$=$CANDOR_CANDIDATE$[.@w]; deletearray($CANDOR_CANDIDATE$); deletearray($CANDOR_VOTES); array_push($CANDOR_CANDIDATE$, ($CANDOR_REPUTATION < 15 ? "Jesus Saves" : $CANDOR_MAYOR$)); array_push($CANDOR_VOTES, 0); // Notify new mayors of their victory rodex_sendmail(gf_charnameid($TULIM_MAYOR$), "Tulimshar Townhall", "Election Victory", "You've been elected to the office!"); rodex_sendmail(gf_charnameid($HALIN_MAYOR$), "Halinarzo Townhall", "Election Victory", "You've been elected to the office!"); rodex_sendmail(gf_charnameid($HURNS_MAYOR$), "Hurnscald Townhall", "Election Victory", "You've been elected to the office!"); rodex_sendmail(gf_charnameid($LOF_MAYOR$), "LoF Townhall", "Election Victory", "You've been elected to the office!"); rodex_sendmail(gf_charnameid($NIVAL_MAYOR$), "Nivalis Townhall", "Election Victory", "You've been elected to the office!"); // Towns where admins are named, instead of elected //rodex_sendmail(gf_charnameid($FROSTIA_MAYOR$), "Frostia Townhall", "Election Victory", "You've been elected to the office!"); //rodex_sendmail(gf_charnameid($CANDOR_MAYOR$), "Candor Townhall", "Election Victory", "You've been elected to the office!"); end; } ///////////////////////// // Dialog helpers // General info // POL_Information( ) function script POL_Information { mesc l("Weekly, at Sunday 00:00, elections are held."); mesc l("The current town administrator will be inscribed for re-election automatically."); mesc l("However, if town has less than 15 reputation, they'll need to re-apply manually, and may lose the office for the bot account."); dnext; mesc l("Town Administrator can use the town money for investments, and also receive a salary depending on how well the town is."); next; mesc l("A player may be the town admin of several different towns."); mesc l("However, an account may only apply for an office weekly."); mesc l("The account with highest votes will win. Ties will be solved by randomness."); mesc l("An account may vote anywhere, but only once per town (weekly)."); next; mesc l("The town administrator benefits for free services on the town."); mesc l("Also, they can control the city taxes, which are applied upon purchases and sales within the town."); mesc l("However, they must visit their town office and do daily paperwork, every day. Otherwise, town reputation will go down."); mesc l("If town reputation reaches zero, the town will only be able to get money with taxes."); return; } // Candidate Info and voting // POL_Candidate( TOWNCODE ) function script POL_Candidate { copyarray( .@cd$, getd("$"+getarg(0)+"_CANDIDATE$"), getarraysize(getd("$"+getarg(0)+"_CANDIDATE$")) ); copyarray( .@vt, getd("$"+getarg(0)+"_VOTES"), getarraysize(getd("$"+getarg(0)+"_VOTES")) ); .@list$="Don't vote"; for (.@i=0;.@i 6) { .@left=6; TOWN_ACTIONS[.@TP]=(gettimeparam(GETTIME_HOUR)/4)-6; } do { .@GP=getd("$"+getarg(0)+"_MONEY"); .@TX=getd("$"+getarg(0)+"_TAX"); .@EX=getd("$"+getarg(0)+"_EXPORT"); .@RP=getd("$"+getarg(0)+"_REPUTATION"); .@CR=getd("$"+getarg(0)+"_TAXOFF"); .@DQ=getd("$"+getarg(0)+"_DAILYQUEST"); .@left=(gettimeparam(GETTIME_HOUR)/4)-TOWN_ACTIONS[.@TP]; mesc l("Town Money: @@", .@GP), 2; mesc l("Town Reputation: %d | %d.%02d %% Tax", .@RP, .@TX/100, .@TX%100), 2; mesc l("Town Weekly Exports: @@", .@EX), 2; mesc l("Total actions left: %d", .@left), (.@left > 1 ? 9 : 1); next; menuint l("Nothing"), 0, rif(.@DQ != gettimeparam(GETTIME_DAYOFMONTH), l("Do some paperwork")), 1, rif(.@left, l("Invest in Exportations")), 10, rif(.@left, l("Invest in Reputation")), 20, rif(.@left, l("Raise city taxes")), 30, rif(.@left, l("Lower city taxes")), 35, rif(.@CR && .@RP, l("Tax crafters")), 40, rif(!.@CR, l("Don't tax crafters")), 41, rif(.@left >= 6, l("Exile a player")), 70, rif(.@left >= 6, l("Revert a player exile")), 71, rif(.@left, l("Raise server wide EXP")), 80, l("Resign"), 99; mes ""; switch (@menuret) { // Mark 0: Cycle case 1: if (rand2(3) == 1) setd(.@town$+"_REPUTATION", limit(0, .@RP+1, 100)); setd(.@town$+"_DAILYQUEST", gettimeparam(GETTIME_DAYOFMONTH)); mesc l("You dealt with paperwork."), 2; break; // Mark 10: Exports case 10: .@cost=.@EX/10; mesc l("Investing in Exportations"), 3; mesc l("You need @@ GP to make this investment.", .@cost); if (.@GP < .@cost) break; mesc l("Are you sure?"); if (askyesno() == ASK_YES) { .@GP=getd("$"+getarg(0)+"_MONEY"); setd(.@town$+"_MONEY", .@GP-.@cost); setd(.@town$+"_EXPORT", .@EX+rand2(4,6)); TOWN_ACTIONS[.@TP]+=1; mesc l("Investment executed"), 2; next; } break; // Mark 20: Reputation case 20: .@cost=.@RP*3; mesc l("Investing in Reputation"), 3; if (.@RP >= 100) { mesc l("Reputation cannot go above 100!"), 1; next; break; } mesc l("You need @@ GP to make this investment.", .@cost); if (.@GP < .@cost) break; mesc l("Are you sure?"); if (askyesno() == ASK_YES) { .@GP=getd("$"+getarg(0)+"_MONEY"); setd(.@town$+"_MONEY", .@GP-.@cost); setd(.@town$+"_REPUTATION", .@RP+1); TOWN_ACTIONS[.@TP]+=1; mesc l("Investment executed"), 2; next; } break; // Mark 30: TAXES and Tax Governance case 30: .@cost=.@TX/11; mesc l("Raising Taxes"), 3; mesc l("You need @@ Reputation to make this investment.", .@cost); mesc l("Taxes will raise in 0.02~0.05%, capped at 15%."); if (.@RP < .@cost || .@TX >= 1500) break; mesc l("Are you sure?"); if (askyesno() == ASK_YES) { setd(.@town$+"_REPUTATION", .@RP-.@cost); setd(.@town$+"_TAX", .@TX+rand2(2,5)); TOWN_ACTIONS[.@TP]+=1; mesc l("Taxes raised"), 1; next; } break; case 35: .@cost=.@TX/30; mesc l("Lowering Taxes"), 3; mesc l("You will gain @@ Reputation.", .@cost); mesc l("Taxes will fall in 0.01~0.03%, capped at 0.00%"); if (.@TX <= 0 || .@RP >= 100) break; mesc l("Are you sure?"); if (askyesno() == ASK_YES) { .@val=.@TX-(.@cost ? rand2(1,3) : 1); setd(.@town$+"_TAX", max(0, .@val)); setd(.@town$+"_REPUTATION", min(100, .@RP+.@cost)); TOWN_ACTIONS[.@TP]+=1; mesc l("Taxes lowered"), 1; next; } break; // Mark 40: Tax Crafters and Town Policies case 40: setd("$"+getarg(0)+"_TAXOFF", false); setd(.@town$+"_REPUTATION", .@RP-1); mesc l("Crafters are now paying taxes."), 1; break; case 41: setd("$"+getarg(0)+"_TAXOFF", true); setd(.@town$+"_REPUTATION", .@RP+1); mesc l("Crafters no longer pays taxes. (Tax exempt)"), 1; break; // Mark 70: Exile and Player functions case 70: mesc l("Exiled players will not be able to save to menhir."), 1; mesc l("A global announcement will be made."), 1; mesc l("Player must be online for the operation to finish."), 1; mesc l("This will cost you all your action points."), 1; next; mesc l("Please insert player name to exile."), 1; input .@ex$; if (.@ex$ == "") break; .@id=getcharid(3, .@ex$); if (.@id < 1) { mesc l("The player is offline or does not exist."); break; } if (.@id == getcharid(3)) { mesc l("You cannot exile yourself!"); break; } .@town=POL_LocToTP(getarg(0)); .@you=getcharid(3); attachrid(.@id); dispbottom l("You have been EXILED from %s by %s.", getarg(0), .@MAYOR$); #EXILED=#EXILED|.@town; .@l$=LocToMap(TPToLoc(.@town)); if (getsavepoint(0) == .@l$) savepoint "000-1", 22, 22; // LOCATION$ will be redefined once you leave so no worries detachrid(); attachrid(.@you); kamibroadcast(sprintf("%s has EXILED %s from %s.", .@MAYOR$, .@ex$, getarg(0))); TOWN_ACTIONS[.@TP]+=6; break; case 71: mesc l("Please insert player name to cancel exile."), 1; mesc l("Player must be online for the operation to finish."), 1; mesc l("This will cost you all your action points."), 1; input .@ex$; if (.@ex$ == "") break; .@id=getcharid(3, .@ex$); if (.@id < 1) { mesc l("The player is offline or does not exist."); break; } .@town=POL_LocToTP(getarg(0)); .@you=getcharid(3); attachrid(.@id); if (#EXILED & .@town) { dispbottom l("You are NO LONGER EXILED from %s by %s.", getarg(0), .@MAYOR$); #EXILED=#EXILED^.@town; } detachrid(); attachrid(.@you); kamibroadcast(sprintf("%s has ANNULED THE EXILE %s from %s.", .@MAYOR$, .@ex$, getarg(0))); TOWN_ACTIONS[.@TP]+=6; break; // Mark 80: Town and Server Governance case 80: .@gcost=50000; .@rcost=25; .@b=5+(.@RP/10); mesc l(".:: Server Boom ::."), 3; mesc l("To cause a server happy hour (+%d%% EXP), you need:", .@b); mesc l("%s GP and %d REP.", fnum(.@gcost), .@rcost); if (.@RP < .@rcost || .@GP < .@gcost) break; mesc l("Are you sure?"); if (askyesno() == ASK_YES) { setd(.@town$+"_REPUTATION", .@RP-.@rcost); setd(.@town$+"_MONEY", .@GP-.@gcost); TOWN_ACTIONS[.@TP]+=1; mesc l("Server Happy Hour Decreed"), 1; // Will not be shown kamibroadcast(sprintf("%s has sponsored a Server Happy Hour using tax money!", .@MAYOR$)); // Effective immediately $@EXP_EVENT=.@b; $@EXP_EVENT_TIME=1; donpcevent "@exprate::OnPlayerCall"; // We must terminate dialog now and close all context for EXPRATE. closeclientdialog; end; } break; // Mark 90: Office case 99: mesc l("Really resign?"), 1; next; if (askyesno() == ASK_YES) { setd(.@town$+"_MAYOR$", "Jesus Saves"); // If you have already received a vote, this will be skipped if (getd(.@town$+"_VOTES[0]") <= 0 && getd(.@town$+"_CANDIDATE$[0]") == strcharinfo(0)) setd(.@town$+"_CANDIDATE$[0]", "Jesus Saves"); mesc l("YOU HAVE RESIGNED THE OFFICE."), 1; close; } default: return; } // End script } while (true); return; }