// TMW2 scripts. // Authors: // Jesusalva // Description: // Controls world seasons. RESPECT MASK_* VARS ON CONSTANTS DB // is_night(set=False) function script is_night { // If we're not configuring, retrieve the variable (cache) // It is more efficient this way .@set=getarg(0, false); if (!.@set) return $@WEATHER_NIGHT; /* // Night time depends on season. // Summer: Day > Night // Winter: Night > Day // Autumn/Spring: Day = Night // // But we have TWO SUNS, meaning night is always smaller. // // 2 = GETTIME_MINUTE // 3 = GETTIME_HOUR // Summer: 5h day. 1h night. (4 cycles, 8 updates) // Others: 3h day. 1h night. (6 cycles, 12 updates) // Winter: 2h day. 1h night. (8 cycles, 16 updates) */ // NEW Unified Rule: Day last 3 hours. Night lasts 1 hour. Always. .@t=(season() == SUMMER ? 6 : (season() == WINTER ? 3 : 4)); return (gettime(3) % .@t == 1); } 000-0,0,0,0 script #WeatherCore NPC_HIDDEN,{ end; /* * removemapflag("", ) * setmapflag("", {, }) * getmapflag("", ) mf_snow: 16 mf_jexp: 39 mf_bexp: 40 */ OnInit: // This is weather startup .@init=true; $@WEATHER_NIGHT=is_night(true); .tpc=0; .tcl=0; // Bind commands bindatcmd "wsnow", "#WeatherCore::OnSnow", 80, 80, 1; bindatcmd "wrain", "#WeatherCore::OnRain", 80, 80, 1; bindatcmd "wsand", "#WeatherCore::OnSand", 80, 80, 1; bindatcmd "wevil", "#WeatherCore::OnEvil", 80, 80, 1; bindatcmd "wnight", "#WeatherCore::OnNight", 80, 80, 1; bindatcmd "wclear", "#WeatherCore::OnClear", 80, 80, 1; bindatcmd "wreset", "#WeatherCore::OnReset", 99, 99, 1; bindatcmd "wset", "#WeatherCore::OnManual", 99, 99, 1; // Determine which maps are subject to weather, and how weather works: // eg. it will never snow on a desert, or a sandstorm on icelands. .wcore = htnew; // Deserts htput(.wcore, "003-1", "desert"); htput(.wcore, "004-1", "desert"); htput(.wcore, "004-2", "desert"); htput(.wcore, "009-1", "desert"); htput(.wcore, "010-1", "desert"); htput(.wcore, "010-2", "desert"); htput(.wcore, "032-1", "desert"); // Woodlands htput(.wcore, "001-4", "woodland"); htput(.wcore, "001-11", "woodland"); htput(.wcore, "001-12", "woodland"); htput(.wcore, "005-1", "woodland"); htput(.wcore, "012-1", "woodland"); htput(.wcore, "014-1", "woodland"); htput(.wcore, "014-2", "woodland"); htput(.wcore, "014-3", "woodland"); htput(.wcore, "014-4", "woodland"); htput(.wcore, "014-5", "woodland"); htput(.wcore, "017-1", "woodland"); htput(.wcore, "018-1", "woodland"); htput(.wcore, "018-2", "woodland"); htput(.wcore, "018-4", "woodland"); htput(.wcore, "018-5", "woodland"); htput(.wcore, "027-1", "woodland"); // Icelands htput(.wcore, "001-7", "iceland"); htput(.wcore, "019-1", "iceland"); htput(.wcore, "019-2", "iceland"); htput(.wcore, "019-3", "iceland"); htput(.wcore, "019-4", "iceland"); htput(.wcore, "019-5", "iceland"); htput(.wcore, "019-6", "iceland"); htput(.wcore, "020-1", "iceland"); htput(.wcore, "022-1", "iceland"); htput(.wcore, "024-1", "iceland"); htput(.wcore, "031-1", "iceland"); // Special htput(.wcore, "011-3", "special"); consoleinfo "[Weather.sys] Total Maps = " + htsize(.wcore); // No "end" here, so server starts with weather OnMinute00: OnMinute15: OnMinute30: OnMinute45: // There is no weather in test servers if (debug && !$@GM_OVERRIDE) end; //debugmes "[Weather.sys] Starting to regen"; .tpc+=getusers(1); .tcl+=1; .@hti = htiterator(.wcore); for(.@key$ = htinextkey(.@hti); hticheck(.@hti); .@key$ = htinextkey(.@hti)) { // Local variables: .@key$ .@type .@r .@type$=htget(.wcore, .@key$); .@r=rand(0,10000); // Clear weather map masks .@mk=getmapmask(.@key$); if (.@mk & MASK_RAIN) .@mk=.@mk^MASK_RAIN; if (.@mk & MASK_SANDSTORM) .@mk=.@mk^MASK_SANDSTORM; if (.@mk & MASK_SNOW) .@mk=.@mk^MASK_SNOW; if (.@mk & MASK_NIGHT) .@mk=.@mk^MASK_NIGHT; if (.@mk & MASK_EVILSANCTUM) .@mk=.@mk^MASK_EVILSANCTUM; // Monster King Sieges (can be weird, siege last 10mn and mask last 15) if ($@MK_SCENE) .@mk=.@mk|MASK_EVILSANCTUM; if (.@mk & (MASK_MATTACK|MASK_EVILSANCTUM)) .@mk=.@mk^MASK_EVILSANCTUM; // Remove all current masks, and add rain/snow/sand if (.@type$ == "desert") { if (.@r < 10) .@mk=.@mk|MASK_RAIN; else if (.@r < 300) .@mk=.@mk|MASK_SANDSTORM; } else if (.@type$ == "woodland") { if (.@r < 300) .@mk=.@mk|MASK_RAIN; if ($EVENT$ == "Christmas") .@mk=.@mk|MASK_SNOW; else if (season() == WINTER && .@r >= 9250) .@mk=.@mk|MASK_SNOW; } else if (.@type$ == "iceland") { if (.@r < 30) .@mk=.@mk|MASK_RAIN; else if (.@r < 300) .@mk=.@mk|MASK_SNOW; } else if (.@type$ == "special") { // This biom is too hot for snow. But it may rain. if (.@r < 300) .@mk=.@mk|MASK_RAIN; // Fog? (Evil Sanctum and Monster Attack) Or Sandstorm? if (.@r % 4 == 2) .@mk=.@mk|MASK_EVILSANCTUM; else if (.@r % 4 == 1) .@mk=.@mk|MASK_SANDSTORM; else if (.@r % 4 == 3) .@mk=.@mk|MASK_MATTACK; } else { consolebug "Warning warning, blame Saulc! Weather system error on map "+.@key$; announce("ERROR BLAME SAULC! WEATHER SYSTEM CORRUPTED.", bc_all); } // Bugfix if (!(.@mk & MASK_NONE)) .@mk=.@mk|MASK_NONE; setmapmask .@key$, .@mk; // Is it night time? if (is_night()) { setmapflag(.@key$, mf_nightenabled); addmapmask .@key$, MASK_NIGHT; } else if (getmapmask(.@key$) & MASK_NIGHT) { removemapflag(.@key$, mf_nightenabled); removemapmask .@key$, MASK_NIGHT; } } htidelete(.@hti); //debugmes "[Weather.sys] Regenerated"; // Hardcore: Skip day/night cycles if ($HARDCORE || $@GM_OVERRIDE) { $@WEATHER_NIGHT=is_night(true); end; } // During night, normal monsters respawn 30% faster. (Bifs and Bosses are immune) // // Also, announce to players about day/night cycle changes // The fastest you'll get is 30 minutes for night cycle. // It's 2 messages every 3 hours. (r7.5) // Player might be on cave, and this will help them tracking time. .@current=is_night(true); .@update = (.@current != $@WEATHER_NIGHT); if (.@update) { $@WEATHER_NIGHT=.@current; if (.tcl > 0) { .tpc = .tpc / .tcl; // Monsters spawn faster based on average player count of previous // cycle, 2% faster per player, capped at 2/3 of the lowest rate // Default lowest is 70%, so it can go down up to 45% reduction // For a total of (70-45 = 25%) or monsters spawning 4× faster // when server is at "full" load (22 players or so) .@bon = min(.tpc * 2, min($BCONFN_SPAWN, $BCONFD_SPAWN) * 2 / 3); } .tpc=0; .tcl=0; } if (is_night() && .@update) { .@c = getunits(BL_PC, .@players, MAX_CYCLE_PC); for (.@i = 0; .@i < .@c; .@i++) { attachrid(.@players[.@i]); callfunc("SC_Bonus", 180, SC_INCMHPRATE, 10, 10); percentheal 100, 100; message(.@players[.@i], "The night falls."); detachrid(); } setbattleflag("mob_spawn_delay", $BCONFN_SPAWN - .@bon); setbattleflag("monster_hp_rate", $BCONFN_MOBHP); //charcommand("@reloadbattleconf"); // Careful! donpcevent("@exprate::OnInheirtedReload"); //donpcevent("@droprate::OnReload"); } else if (!is_night() && .@update) { .@c = getunits(BL_PC, .@players, MAX_CYCLE_PC); for (.@i = 0; .@i < .@c; .@i++) { attachrid(.@players[.@i]); callfunc("SC_Bonus", 180, SC_INCMHPRATE, 10, 10); percentheal 100, 100; message(.@players[.@i], "The day rises."); detachrid(); } setbattleflag("mob_spawn_delay", $BCONFD_SPAWN - .@bon); setbattleflag("monster_hp_rate", $BCONFD_MOBHP); //charcommand("@reloadbattleconf"); // Careful! donpcevent("@exprate::OnInheirtedReload"); //donpcevent("@droprate::OnReload"); } callfunc "FYE_Normalize"; debugmes "[Weather.sys] Weather reloaded"; end; // Function to check stuff // WeatherSwitch ( MASK, MAP ) function WeatherSwitch { // Get map getmapxy(.@key$,.@a,.@b,0); // Sanitize .@m$ = htget(.wcore, .@key$, "Not found"); // Change Weather or abort if (.@m$ == "Not found") dispbottom l("Command not permitted on this map! Check npc/functions/weather.conf"); else addmapmask(.@key$, getarg(0)); return; } // Some commands, for GMs manually override weather OnRain: WeatherSwitch(MASK_RAIN); end; OnSand: WeatherSwitch(MASK_SANDSTORM); end; OnSnow: WeatherSwitch(MASK_SNOW); end; OnNight: WeatherSwitch(MASK_NIGHT); end; OnEvil: WeatherSwitch(MASK_EVILSANCTUM); end; OnManual: if (!.@atcmd_numparameters) { dispbottom l("Syntax: @wset "); end; } // Never allow negative numbers, or to disable map mask 1 (never, EVER, do such insane thing) .@rq = atoi(.@atcmd_parameters$[0]); if (.@rq <= 1 || .@rq % 2 == 1) { dispbottom l("Invalid map mask"); end; } // getmapxy(.@key$,.@a,.@b,0); .@mk=getmapmask(.@key$); .@mk=.@mk^.@rq; setmapmask(.@key$, .@mk); end; // Clear works on any map OnClear: getmapxy(.@key$,.@a,.@b,0); .@mk=getmapmask(.@key$); if (.@mk & MASK_RAIN) .@mk=.@mk^MASK_RAIN; if (.@mk & MASK_SANDSTORM) .@mk=.@mk^MASK_SANDSTORM; if (.@mk & MASK_SNOW) .@mk=.@mk^MASK_SNOW; if (.@mk & MASK_NIGHT) .@mk=.@mk^MASK_NIGHT; setmapmask(.@key$, .@mk); end; // Reset the whole map, including season, event and weather masks OnReset: getmapxy(.@key$,.@a,.@b,0); setmapmask(.@key$, MASK_NONE); end; }