From d84b29eac348970306bf6dcb3b480dee4bc6d010 Mon Sep 17 00:00:00 2001 From: Acentech Dev Date: Sun, 19 Jul 2026 15:47:05 +0300 Subject: [PATCH] feat(maps): add Acheron, Debenter, Uruk, Ferea (maps 83-86) Same pattern as Arkania: terrain resources Terrain84-87.att, map initializer classes, registration, and update-plugin (v97) that creates each map + spawn gate + /move warp AND assigns it to the game server configuration so it is hosted. Also fix the Arkania update-plugin to assign the game server config (was missing). Co-Authored-By: Claude Opus 4.8 (1M context) --- ...e.OpenMU.Persistence.Initialization.csproj | 8 ++ .../Initialization/Resources/Terrain84.att | Bin 0 -> 65539 bytes .../Initialization/Resources/Terrain85.att | Bin 0 -> 65539 bytes .../Initialization/Resources/Terrain86.att | Bin 0 -> 65539 bytes .../Initialization/Resources/Terrain87.att | Bin 0 -> 65539 bytes .../Updates/AddArkaniaMapUpdateSeason6.cs | 21 ++-- .../Updates/AddImportedMapsUpdateSeason6.cs | 100 ++++++++++++++++++ .../Initialization/Updates/UpdateVersion.cs | 5 + .../VersionSeasonSix/GameMapsInitializer.cs | 4 + .../VersionSeasonSix/Maps/Acheron.cs | 40 +++++++ .../VersionSeasonSix/Maps/Debenter.cs | 40 +++++++ .../VersionSeasonSix/Maps/Ferea.cs | 40 +++++++ .../VersionSeasonSix/Maps/Uruk.cs | 40 +++++++ 13 files changed, 292 insertions(+), 6 deletions(-) create mode 100644 src/Persistence/Initialization/Resources/Terrain84.att create mode 100644 src/Persistence/Initialization/Resources/Terrain85.att create mode 100644 src/Persistence/Initialization/Resources/Terrain86.att create mode 100644 src/Persistence/Initialization/Resources/Terrain87.att create mode 100644 src/Persistence/Initialization/Updates/AddImportedMapsUpdateSeason6.cs create mode 100644 src/Persistence/Initialization/VersionSeasonSix/Maps/Acheron.cs create mode 100644 src/Persistence/Initialization/VersionSeasonSix/Maps/Debenter.cs create mode 100644 src/Persistence/Initialization/VersionSeasonSix/Maps/Ferea.cs create mode 100644 src/Persistence/Initialization/VersionSeasonSix/Maps/Uruk.cs diff --git a/src/Persistence/Initialization/MUnique.OpenMU.Persistence.Initialization.csproj b/src/Persistence/Initialization/MUnique.OpenMU.Persistence.Initialization.csproj index 310b825..00da802 100644 --- a/src/Persistence/Initialization/MUnique.OpenMU.Persistence.Initialization.csproj +++ b/src/Persistence/Initialization/MUnique.OpenMU.Persistence.Initialization.csproj @@ -25,6 +25,10 @@ + + + + @@ -105,6 +109,10 @@ + + + + diff --git a/src/Persistence/Initialization/Resources/Terrain84.att b/src/Persistence/Initialization/Resources/Terrain84.att new file mode 100644 index 0000000000000000000000000000000000000000..26fe41558b6c301f2101d6e29b3b3f70d98ee58b GIT binary patch literal 65539 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 literal 0 HcmV?d00001 diff --git a/src/Persistence/Initialization/Resources/Terrain86.att b/src/Persistence/Initialization/Resources/Terrain86.att new file mode 100644 index 0000000000000000000000000000000000000000..c0bcb3a6dbe0bf17dc102c43325b283ad14698c5 GIT binary patch literal 65539 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 RxVTS`qyoAb45D8c{6E-NUzY#? literal 0 HcmV?d00001 diff --git a/src/Persistence/Initialization/Resources/Terrain87.att b/src/Persistence/Initialization/Resources/Terrain87.att new file mode 100644 index 0000000000000000000000000000000000000000..a67a76fa75f1476670407dfde83bd450df73900d GIT binary patch literal 65539 zcmeHP+mal~t&>megC6$(f7d6OOn@MhS(jF8*N%0EV-f_wTUB*yq?z@PfB*Z>_Vvd< z;R^ik{{JJcz~S!yC%pgvl8>N%|F^gPhrQk={YUuQ{a;QtxBrj3 z0MBm8ll|vv7v)Tvub0>DrTuA-HO#Y#9_%0W4g=FLbw83tsJi zc#E^+Y{1At*VH)JPI@?2S0o&UU>*7lkUfF>{qO3DKAT89;ojNC3YX}4-fYQ{7m!rK z@EJ0CF?1x*?Vk)t_bOQ$(JC%#Vk{^*RTnv%#h4n+1Q!LOjbwQ_5Yk8B{r-7HRBKPG z+X&LGF^C$ulT2X>&?ebdp)d{vT9~A;>_l_D9;NIj8U#9hSPn(2!*(ym3+uYM^A5Kw$DC zSo%2dg5pKN^1R(Y@|j~>M8KUEwGuqCps_AbR)sw7ubvCsw-lD}`}?o!;T`gZyi_te zClSuC8Hr_K`~-Am$qBgIKYB^hAagWbq(nA>`~cIKzEEx0MJ)>rO%-YcHE9TJCE)S? zl4JcPL`$I-bVYf1vYE(y)$G>4m9^25wR_$RZ;*S{R680B?+{ z>3p+)6ud&)mZ_g++T{pQ6p)j$Ks3u>=tc`2i9`=2Skn1)|0wqwrG7Kp7ns9}7=;(< zMBQnKbh^<()}aPKr3DZ7N3l=N)Yl5E1rqN;l(#q{MJmj!B~EN#)I2cx7F_RNN_`gY zeZ9`kr`b~=oktoYD}f-&fhlJg1YPc53XD+t?c#}%b`Ga;V~seK5Ps&ZSW_nNU&Jj? z3<2NlFU1Fx${U7K{x=oY~qG8z|^gLIRVXrM! zl5rZQxTaB6lFo2XNQ+r}Pj({gi%a7y@~nk(}QDVEvqKr6T=wt<#iD)w~|l zI)FQHEib214?ghXrX{h7ezZXr(7h zPjW?yV=vr)O&4dStybl*G`ognqlEYx+~$#iOk0hn4NaMI+Fz4sZU74A6Gmkxr^Ht= zI@T^DUVV~6d%wS?(At303b3j^IVHY}(b7(-9FZHAMz1)@&HIK32E=xPYfmw@x{%W7$CY`sztxGVfwX?G4N@a;W5ZaTG&p4D^I$gmY^0J*C`DBO zG&x1B*C!8WMW3}rnQzY+dHRlgmQ(1dkAx9ZgQ1fQbq{( zHh&^KDBk5r2Q2GUjZ!onR5++V1(7<@leCgDLS!ukp`Avp*ww`?Yk#bSl*epmM@W|x zA@>wWuE8g1B}LMfqD7=;lXs%Dg52F0?@6MxPW3dXb(VIST64m@6m1Z=Njp-JHITT# z3zZ;rJ0VQY0u>#@5@+I>kdwnrw45tuUIH{f0h%d(&_WSH^ON-4dqzh?_QsVnekK7# zBq2z*{sH9wnqm<`m+p3kx8KDbKvDjFHUIou3EM=;aJBf%lc}c4%o;ig1j55#A z$gV~&SlJOvCl9hm*Tg@#|$xNmXAlRR>~!nQw@RTX{EL6lKN(M;Nr+`)^zlqtvL07t1_WPd#&5xN^fS&o9ld3c5xQ0QM4%9L5Im_&zzdh@5;3_0_Det={}rwb zGQvaIWjv@#Yf0lZK44AX@PG0CbC<);N^d)pu;s^#@z;TlF|l>nND>eGFaLBi_YBTe zef_)rf8hdcL)k1FN#Z=|QDN>898>ulz!wga)>Yb$n>3S;L-oRgimB?>q3L*46DwVL zeqsN9$qV*+4&PQ+RBUD4ks4fwEkO8tjXpe`t!j` zuPoMutqtTTNxvmnYewyUZ?LbHdtkP@(R(0`(6m^R{~JM?A)0pR!Ah?z)+4Q;kqnSL zUk`K$Xz{A{IHu8aLs^WVF(R!?nn@M^PXW^W+<I zE80^r(NgM2koP&MB(OE0>Iy@EEg^`!LGaH|&VIAMkLF#@V?rrs9!|tuk3#mRC~uIY z2SLvMaQ}-jDHV`LQ*8=LOiX)@jQ;bd?m**1pt;0*E(Tf(!u7^vcuu5cfpCt0l~r*H zN=#h(Mt1$zEmfXi?yO)>#6U|ySoeSW{H}pcpQpqy*eE(0VBdoBerT-5Sn{Rw?_T1f|lL z{Olu(PXnw{hP_jIPxK7PXR0`DPxRkL_O(N5; zdcObSF0ftUi~ETqvz{URm7x}**$zY!}lk|X5D7cC)_K);}tj46i`IN+9(T$CQ8mMI>ok)_% zZQ!uK?#$vUr!q9yTFTMe2*B{^iN$w6gMw_jJl-zAD)loG# zFm_Hhh%j|%`c#O-g4zv!Wq;Jy?!+!KtYFAWq0~H05JG)BHe+HXGsEAu{~Vx9kv5of zq#;X?2A!HP#aqMLSTYmr*MIu=pYC6eQu!I^Y@4cL!OJUbWDB{VX*&xhGBf%s_Sdm; z_sfy-v}1*NB0rH9xUkV6kXO(1{*SI^lU_TF7(-yAWTCi$Wh=b1g&g}2MmkkJwUpq` z{PTb8Gaa=?#4G^6oYV-KJZc6)uV~sTIj`bQZj2JCp9X*D{$oHNMJG-8#r`R83v}g# z&--sRgkTA|?|{?*_Pk)+6LCRPE}UO9CDRj>0=h8Ec4F#s4j*$Hz%nImh7=u0I+TqP zBEgxE7z>OQG6jdv0Ce8YZh^t&4${ma%XH}!9Y`{iof1aiR=_o*lS_ibhafs{XSaat zpF7!=pS@V7OQ+~ShJ&(G!U)_7xMp;6Nzm{AuYdguz027xkoVVaXv`vAIzH8Vd|`k%`#=8d`PY}#(U`c~za(P@DIwHiGlK|i5c@e>GYSXh@#uK5k5(f=VrDNQT^smhPXmf+ z@xdgc?BDX4JVa63P<#KgF0yl|xFBuF4D0K8p4R^Ner z=kM1*wDA`}iM|QPh*pl1Dwutokd|}^*W{bpStqBd1<$|v%nKmGZ`hx+JpwXI3-=;s zBP%(RlemTT0qFKe@mgT;m1<&SKRlZXiQ3DUOjf*;lej|rws(C7gw*WM+GX3j`d&1$ zAEKD0M_U=Qk(8XtNnGGsy}SXo{aJZ{RAC8;YXZ%Ggqs?LDrHOsrB35CF8G7}wH!Js zS31m)z6wmO+>E;_nM-L?O3We1HSp-y`(OUCE7yt=!Ux$QG0scnF`TLbL%TS4E10V@ z7nJ)i!ua+@qU{brOKm{5r#P2x46PyqQo91vECwWBonq%FU%CDE?Q61K)uZMa7N*=8 z&_pr$L?%SuUM!eYWYA2$1d*?gzp%fsKO1YgG}sc-=*$u@eT;KCM5)LiX}<)>9%nrM zLe9UvX#A}1%#g-fVW-KMje&qtPOA}{oxuQ-egP%pw155n_o5o5S(ecN(kEyqBc3h^ zPmsl6Fv2i}hudq0+<*D!zj6QT{!ePpK``AsyU~nmOo{3O)Cx`OY*m-7Hk&j`jWh0l z{t3vozc#Zg7-JB5S%w2hBhtn(FtDd383Ae`esZpyYDKBMe!2kt{v#3dPM8aOS>>Wp z>};HRe((OHQ|@N1IhNl2fyw{z$IqYP5<0=O1f@yCy!%^M)(g`~bg=s|f|aku?&KiYo`r7baIaA4ZgZ6Zb9wmykr-)uqzOg>8wsqQ~S zyCO14zrTJ<%)2dRS%4gw9Y_q^ja?xb}Pog6c!H`Xqj@)UCizMXE94) z5Tz$|EPo+*tqa2gN#<$cgA(oY&%3WHk7C+n)i&xuo898IcK!{c^K|$@t?~A+@BguV z{F{iB9n~cAwI}hQ&2I5hJO75!acs6c-=iDT?LXcWcmh&~vOoI0nK-;(*k6a6e+uja zM!y5P-oJFH*Y{U;_?6tXOPy|8|Ms0ZKmNAoA2+|OJG!Qh2o6{FhW_>a(f{JSnZf?` zYyb9#>z8%C*xs!)F+-uc(Cc){k(()@dWFlcVeV18e^_&E=QB5>NEpcVL`86y9L^4D zv!+r*bybwJ{rOp^g5y*%%POg|c%=es5^=~Ei0*gbqT-as{^NCaMYqipl0NQaH@^{7 z6|~Mms{aixWw!8ce@?t*P6DGqMQkTHJyj=GL*P__-nSs?_2?J(#~np+9S@wIsuQaL z*hNIV3(R>6Sm6R(J^$={%3p&lIgQn%Bpt!oM+Mf`Co5cl%MSotfKxsuavjk;x0Iwt zaQ0CN^Gn1E7vOsTn+w2sW&=hBww6hK60pJ(bL(M+3$XtHD4V^obB2=|T^GF(VGrpc zvQ)F;9z0AFTQmocK9j;Y4a|H?N2oNbvH z6AXd416o~i=e^=Q_sY?0t7k7xHcgcRO)^2_hgj<+e4Fp?Wz*C)lfx0@Oie0#q}nM+ zNhM3Q6V_rCpK`#%KVt;*gd?3;dpMNWMDWGJ_qKUckSZbj&8gihW*r%rP|VXOu|dz} zIYJ?eS3;!GEQHtsy8iLkDAXa8#TthtmaVIhxoON)iM-S#(LCSp)=%qeP|96|vvjMo zX{#z(YK%}-!(PkTRkvDFygVNtsn}&OTQm-B-N-_P(@Bfx#+yfo2Bx18M$wN@Q@*FX z`mUv}yR1xDovpF4i_^3XpZ1S*R<_(3;H2`Tk!AafX&~lF79goLfXPnNYCQdmthpNh z(EV!>jR#J7MVp}-&NwpF6D*Lb8-}Sn!@SfWHgvf^uj-bTFF1y1Y&!+>x^FN94Fsh- z;c3rEpls9(LUS~JM@FfXpu&!64M3Aq3=^PzvNJM7njmGBfTj+Fw^2i!sO)cJ6vruS zY9p0WlMBtI6^#IVoJ}&RaP5euu4rBFM|uND>Mh(Gvvx>Z6-Y~1;fNr_x#bEGE<={h z0^%Z9?csT{KeCwxqB)00S*9#N&0~Zm%judcG4j?q6~)V1YzU>0UAVg!(r69h7S-C3 zU#R%Gf%yauWU#Y&!8k~A+qe81|{xrsVMfLM3e%jOQwdAm#iaDm)0MGB&n|#s}pxe16sptkN^BPLEtK2z=7$j|n;#+X{Oh$|r zGgSL;-anp5cJF{rH*_6v$4!CVWQ-V7r0%XS%!XWj5+TKehGQY~hpsDoof-AN5w%)~rq(C-j?MB1Vj zK|>EB?SPo3`XCWfcTU3=BM)y&#vcJ`!F=KFA+wGEHPkRTgplnVoQ5q%9-NHdgIpi^ znZ1jUb#LKd%zP^Qt4~Y>t9~=niU>&|t^R8NgJH zfiHdy50-WA^;f|VO2$QK(;QnzK|x+j2-_!xTOj>i69Vu!1PpS{A`&mizPr>g;|JgN z8ovNsT3eY~k)<<0+051mF1buWO;jc*>Kfl%4YJoBikX@Yhvx3>O~itTIYA zXGwhs+V$7!!h`kY{#N_63dz*(0_*UoBG)hbb3|4lvjJFK@MtqF zVyH<%ZgZ~DrV?Wg)OdI5+5S>@{0Bf$S!P6OD>&#fe_UmxEI-1V6V;njX3Mbgen#c8 zvVR&{Y7gEc8kWcy23{rtu>_Rb3FgU4l$^g1l(MmZ%x5S%Xyl%yd5|bP=H^g2M4X*&uy-aQ1{1pt1ABmkj`t^n}FR~LhuvvVrLkR zR0`I0`p3^cSY=Au2Vt!^35b${Vi4EaPSubl?Pb^$bc*}W z!LPqa&tl99qv0YpP-Fc6#~!B>Ar*QTNR>{q=*PJmmWjN9K0AWH^>N3Msu0xPRWL+}{;Sqht{N4eTd6vTsVe z_gE@~*nfRKd*)crK-y9s|Eze*`>!#@GxV;*lbYk(|N0+5rzUCtq{OAk^qc6(gz9-y z+kUhE{&ly%+~-%#pPBFH%Z_JN&6V@c(f$6M9XX-atZXV8q{9uqnW<&cQ z@Tug@CAofHtX{3=L=}ch=21N8@m(2T_Ggs6Kv? new(2026, 07, 19, 12, 0, 0, DateTimeKind.Utc); /// - protected override ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) { - // Idempotency guard: skip if Arkania (83) already exists. + // Idempotency guard: skip if Arkania (82) already exists. if (gameConfiguration.Maps.Any(m => m.Number == Arkania.Number)) { - return default; + return; } var initializer = new Arkania(context, gameConfiguration); - initializer.Initialize(); // creates map 83 + loads terrain from Terrain84.att + initializer.Initialize(); // creates map 82 + loads terrain from Terrain83.att initializer.SetSafezoneMap(); var arkania = gameConfiguration.Maps.First(m => m.Number == Arkania.Number); + // Host the map on every game server configuration (fresh seeds do this + // automatically, but existing databases need it added explicitly). + var serverConfigs = await context.GetAsync().ConfigureAwait(false); + foreach (var serverConfig in serverConfigs) + { + if (serverConfig.Maps.All(m => m.Number != Arkania.Number)) + { + serverConfig.Maps.Add(arkania); + } + } + // Spawn gate on a walkable tile (center of the map; attr 0x00, verified walkable). var spawnGate = context.CreateNew(); arkania.ExitGates.Add(spawnGate); @@ -76,7 +87,5 @@ public class AddArkaniaMapUpdateSeason6 : UpdatePlugInBase warp.LevelRequirement = 10; warp.Gate = spawnGate; } - - return default; } } diff --git a/src/Persistence/Initialization/Updates/AddImportedMapsUpdateSeason6.cs b/src/Persistence/Initialization/Updates/AddImportedMapsUpdateSeason6.cs new file mode 100644 index 0000000..13f05a0 --- /dev/null +++ b/src/Persistence/Initialization/Updates/AddImportedMapsUpdateSeason6.cs @@ -0,0 +1,100 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Updates; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps; +using MUnique.OpenMU.PlugIns; + +/// +/// Adds the four imported maps Acheron (83), Debenter (84), Uruk (85) and Ferea (86): +/// the map definitions with their terrain, a spawn gate and a /move warp each, and +/// assigns each to the game server configuration so it is hosted and its spawns run. +/// Monsters and NPCs are added afterwards via the admin panel. +/// +[PlugIn] +[Display(Name = PlugInName, Description = PlugInDescription)] +[Guid("3D9C1B72-7C3F-4E8B-AF14-E29D47A8B012")] +public class AddImportedMapsUpdateSeason6 : UpdatePlugInBase +{ + internal const string PlugInName = "Add imported maps (Acheron, Debenter, Uruk, Ferea)"; + internal const string PlugInDescription = "Adds maps 83-86 (Acheron, Debenter, Uruk, Ferea) with terrain, spawn gate and /move warp, hosted by the game server. Monsters/NPCs are added via the admin panel."; + + /// + public override UpdateVersion Version => UpdateVersion.AddImportedMapsSeason6; + + /// + public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override bool IsMandatory => true; + + /// + public override DateTime CreatedAt => new(2026, 07, 19, 15, 0, 0, DateTimeKind.Utc); + + /// + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + var serverConfigs = (await context.GetAsync().ConfigureAwait(false)).ToList(); + + AddMap(context, gameConfiguration, serverConfigs, new Acheron(context, gameConfiguration), Acheron.Number, Acheron.Name, 84, 127, 126); + AddMap(context, gameConfiguration, serverConfigs, new Debenter(context, gameConfiguration), Debenter.Number, Debenter.Name, 85, 132, 105); + AddMap(context, gameConfiguration, serverConfigs, new Uruk(context, gameConfiguration), Uruk.Number, Uruk.Name, 86, 128, 128); + AddMap(context, gameConfiguration, serverConfigs, new Ferea(context, gameConfiguration), Ferea.Number, Ferea.Name, 87, 128, 128); + } + + private static void AddMap(IContext context, GameConfiguration gameConfiguration, IList serverConfigs, IMapInitializer initializer, byte number, string name, short warpIndex, byte x, byte y) + { + // Idempotency guard: skip if the map already exists. + if (gameConfiguration.Maps.Any(m => m.Number == number)) + { + return; + } + + initializer.Initialize(); // creates the map + loads terrain from Terrain{number+1}.att + initializer.SetSafezoneMap(); + + var map = gameConfiguration.Maps.First(m => m.Number == number); + + // Spawn gate on a walkable tile. + var spawnGate = context.CreateNew(); + map.ExitGates.Add(spawnGate); + spawnGate.Map = map; + spawnGate.X1 = x; + spawnGate.Y1 = y; + spawnGate.X2 = x; + spawnGate.Y2 = y; + spawnGate.IsSpawnGate = true; + + // /move warp entry. + if (gameConfiguration.WarpList.All(w => w.Name != name)) + { + var warp = context.CreateNew(); + gameConfiguration.WarpList.Add(warp); + warp.Index = warpIndex; + warp.Name = name; + warp.Costs = 5000; + warp.LevelRequirement = 10; + warp.Gate = spawnGate; + } + + // Host the map on every game server configuration (fresh seeds do this + // automatically, but existing databases need it added explicitly). + foreach (var serverConfig in serverConfigs) + { + if (serverConfig.Maps.All(m => m.Number != number)) + { + serverConfig.Maps.Add(map); + } + } + } +} diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index 891f5fe..4ef0224 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -489,4 +489,9 @@ public enum UpdateVersion /// The version of the . /// AddArkaniaMapSeason6 = 96, + + /// + /// The version of the (Acheron, Debenter, Uruk, Ferea). + /// + AddImportedMapsSeason6 = 97, } \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/GameMapsInitializer.cs b/src/Persistence/Initialization/VersionSeasonSix/GameMapsInitializer.cs index d9b0b40..d85548d 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/GameMapsInitializer.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/GameMapsInitializer.cs @@ -101,6 +101,10 @@ public class GameMapsInitializer : GameMapsInitializerBase yield return typeof(FortressOfImperialGuardian3); yield return typeof(FortressOfImperialGuardian4); yield return typeof(Arkania); + yield return typeof(Acheron); + yield return typeof(Debenter); + yield return typeof(Uruk); + yield return typeof(Ferea); } } } \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/Maps/Acheron.cs b/src/Persistence/Initialization/VersionSeasonSix/Maps/Acheron.cs new file mode 100644 index 0000000..1e4b67e --- /dev/null +++ b/src/Persistence/Initialization/VersionSeasonSix/Maps/Acheron.cs @@ -0,0 +1,40 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps; + +using MUnique.OpenMU.DataModel.Configuration; + +/// +/// The initialization for the Acheron map (imported map). Seeded empty; monster/NPC +/// spawns and gates are added via the admin panel. +/// +internal class Acheron : BaseMapInitializer +{ + /// + /// The Number of the Map. + /// + internal const byte Number = 83; + + /// + /// The Name of the Map. + /// + internal const string Name = "Acheron"; + + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public Acheron(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + protected override byte MapNumber => Number; + + /// + protected override string MapName => Name; +} diff --git a/src/Persistence/Initialization/VersionSeasonSix/Maps/Debenter.cs b/src/Persistence/Initialization/VersionSeasonSix/Maps/Debenter.cs new file mode 100644 index 0000000..36454d5 --- /dev/null +++ b/src/Persistence/Initialization/VersionSeasonSix/Maps/Debenter.cs @@ -0,0 +1,40 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps; + +using MUnique.OpenMU.DataModel.Configuration; + +/// +/// The initialization for the Debenter map (imported map). Seeded empty; monster/NPC +/// spawns and gates are added via the admin panel. +/// +internal class Debenter : BaseMapInitializer +{ + /// + /// The Number of the Map. + /// + internal const byte Number = 84; + + /// + /// The Name of the Map. + /// + internal const string Name = "Debenter"; + + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public Debenter(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + protected override byte MapNumber => Number; + + /// + protected override string MapName => Name; +} diff --git a/src/Persistence/Initialization/VersionSeasonSix/Maps/Ferea.cs b/src/Persistence/Initialization/VersionSeasonSix/Maps/Ferea.cs new file mode 100644 index 0000000..9bba6fc --- /dev/null +++ b/src/Persistence/Initialization/VersionSeasonSix/Maps/Ferea.cs @@ -0,0 +1,40 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps; + +using MUnique.OpenMU.DataModel.Configuration; + +/// +/// The initialization for the Ferea map (imported map). Seeded empty; monster/NPC +/// spawns and gates are added via the admin panel. +/// +internal class Ferea : BaseMapInitializer +{ + /// + /// The Number of the Map. + /// + internal const byte Number = 86; + + /// + /// The Name of the Map. + /// + internal const string Name = "Ferea"; + + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public Ferea(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + protected override byte MapNumber => Number; + + /// + protected override string MapName => Name; +} diff --git a/src/Persistence/Initialization/VersionSeasonSix/Maps/Uruk.cs b/src/Persistence/Initialization/VersionSeasonSix/Maps/Uruk.cs new file mode 100644 index 0000000..05cd401 --- /dev/null +++ b/src/Persistence/Initialization/VersionSeasonSix/Maps/Uruk.cs @@ -0,0 +1,40 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps; + +using MUnique.OpenMU.DataModel.Configuration; + +/// +/// The initialization for the Uruk map (imported map). Seeded empty; monster/NPC +/// spawns and gates are added via the admin panel. +/// +internal class Uruk : BaseMapInitializer +{ + /// + /// The Number of the Map. + /// + internal const byte Number = 85; + + /// + /// The Name of the Map. + /// + internal const string Name = "Uruk"; + + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public Uruk(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + protected override byte MapNumber => Number; + + /// + protected override string MapName => Name; +}