From 566d54197ae8c140cb6e779595388bec92e0eda3 Mon Sep 17 00:00:00 2001 From: Regalis Date: Fri, 12 Jun 2015 16:56:51 +0300 Subject: [PATCH] Saving (wip), statuseffect refactoring, multiple character faces --- Subsurface/Characters/Character.cs | 28 ++- Subsurface/Characters/CharacterInfo.cs | 60 ++++-- Subsurface/Characters/DelayedEffect.cs | 19 +- Subsurface/Characters/Limb.cs | 4 + Subsurface/Characters/StatusEffect.cs | 84 ++++---- .../Human/{fhead.png => fhead1.png} | Bin .../Content/Characters/Human/fhead2.png | Bin 0 -> 2563 bytes .../Characters/Human/{head.png => head1.png} | Bin Subsurface/Content/Characters/Human/head3.png | Bin 0 -> 2266 bytes Subsurface/Content/Characters/Human/head4.png | Bin 0 -> 2143 bytes Subsurface/Content/Characters/Human/human.xml | 4 +- .../Content/Items/Clothes/captainhat.png | Bin 0 -> 324 bytes Subsurface/Content/Items/Clothes/clothes.xml | 16 ++ .../Content/Items/Diving/divinggear.xml | 4 +- Subsurface/DebugConsole.cs | 8 + Subsurface/GUI/GUI.cs | 2 +- Subsurface/Game1.cs | 1 - Subsurface/GameSession/CrewManager.cs | 45 ++++- Subsurface/GameSession/GameSession.cs | 162 ++++++++++------ Subsurface/Items/Components/Container.cs | 38 +--- Subsurface/Items/Components/Door.cs | 9 +- Subsurface/Items/Components/ItemComponent.cs | 8 +- Subsurface/Items/Components/RepairTool.cs | 4 +- Subsurface/Items/Components/Wearable.cs | 20 +- Subsurface/Items/Item.cs | 47 +++-- Subsurface/Map/Map.cs | 9 +- Subsurface/Networking/GameClient.cs | 2 +- Subsurface/Networking/GameServer.cs | 4 +- Subsurface/SaveUtil.cs | 181 ++++++++++++++++++ Subsurface/Screens/LobbyScreen.cs | 5 +- Subsurface/Screens/MainMenu.cs | 33 ++-- Subsurface/Screens/NetLobbyScreen.cs | 5 +- Subsurface/Subsurface.csproj | 28 ++- Subsurface/ToolBox.cs | 78 ++++---- Subsurface_Solution.v12.suo | Bin 227328 -> 249856 bytes 35 files changed, 640 insertions(+), 268 deletions(-) rename Subsurface/Content/Characters/Human/{fhead.png => fhead1.png} (100%) create mode 100644 Subsurface/Content/Characters/Human/fhead2.png rename Subsurface/Content/Characters/Human/{head.png => head1.png} (100%) create mode 100644 Subsurface/Content/Characters/Human/head3.png create mode 100644 Subsurface/Content/Characters/Human/head4.png create mode 100644 Subsurface/Content/Items/Clothes/captainhat.png create mode 100644 Subsurface/Content/Items/Clothes/clothes.xml create mode 100644 Subsurface/SaveUtil.cs diff --git a/Subsurface/Characters/Character.cs b/Subsurface/Characters/Character.cs index c9eff264b..cb5f938dc 100644 --- a/Subsurface/Characters/Character.cs +++ b/Subsurface/Characters/Character.cs @@ -14,7 +14,7 @@ using Subsurface.Particles; namespace Subsurface { - class Character : Entity, IDamageable + class Character : Entity, IDamageable, IPropertyObject { public static List characterList = new List(); @@ -40,12 +40,14 @@ namespace Subsurface public byte largeUpdateTimer; public readonly Dictionary properties; + public Dictionary ObjectProperties + { + get { return properties; } + } protected Key selectKeyHit; - protected Key actionKeyHit; - protected Key actionKeyDown; - protected Key secondaryKeyHit; - protected Key secondaryKeyDown; + protected Key actionKeyHit, actionKeyDown; + protected Key secondaryKeyHit, secondaryKeyDown; private Item selectedConstruction; private Item[] selectedItems; @@ -83,6 +85,14 @@ namespace Subsurface //which AIstate each sound is for private AIController.AiState[] soundStates; + public string Name + { + get + { + return speciesName; + } + } + public Inventory Inventory { get { return inventory; } @@ -344,10 +354,10 @@ namespace Subsurface animController.FindHull(); - if (info.ID >= 0) - { - ID = info.ID; - } + //if (info.ID >= 0) + //{ + // ID = info.ID; + //} characterList.Add(this); } diff --git a/Subsurface/Characters/CharacterInfo.cs b/Subsurface/Characters/CharacterInfo.cs index e6ae2ab79..17f4177e2 100644 --- a/Subsurface/Characters/CharacterInfo.cs +++ b/Subsurface/Characters/CharacterInfo.cs @@ -1,4 +1,5 @@ -using System.Xml.Linq; +using Microsoft.Xna.Framework; +using System.Xml.Linq; namespace Subsurface { @@ -6,27 +7,28 @@ namespace Subsurface class CharacterInfo { - //the name of the character (e.q. Urist McEngineer) public string name; public readonly string file; - public int ID; + public readonly int headSpriteId; + + //public int ID; public Gender gender; public int salary; - public string GenderString() - { - return gender.ToString(); - } + //public string GenderString() + //{ + // return gender.ToString(); + //} public CharacterInfo(string file, string name = "", Gender gender = Gender.None) { this.file = file; - ID = -1; + //ID = -1; XDocument doc = ToolBox.TryLoadXml(file); if (doc == null) return; @@ -35,7 +37,7 @@ namespace Subsurface if (ToolBox.GetAttributeBool(doc.Root, "genders", false)) { - if (gender==Gender.None) + if (gender == Gender.None) { float femaleRatio = ToolBox.GetAttributeFloat(doc.Root, "femaleratio", 0.5f); this.gender = (Game1.random.NextDouble() < femaleRatio) ? Gender.Female : Gender.Male; @@ -45,7 +47,21 @@ namespace Subsurface this.gender = gender; } } - + + Vector2 headSpriteRange = ToolBox.GetAttributeVector2(doc.Root, "headid", Vector2.Zero); + if (headSpriteRange == Vector2.Zero) + { + headSpriteRange = ToolBox.GetAttributeVector2( + doc.Root, + this.gender == Gender.Female ? "femaleheadid" : "maleheadid", + Vector2.Zero); + } + + if (headSpriteRange != Vector2.Zero) + { + headSpriteId = Game1.localRandom.Next((int)headSpriteRange.X, (int)headSpriteRange.Y + 1); + } + if (!string.IsNullOrEmpty(name)) { this.name = name; @@ -69,8 +85,30 @@ namespace Subsurface this.name += ToolBox.GetRandomLine(lastNamePath); } } - + } + public CharacterInfo(XElement element) + { + name = element.Name.ToString(); + + string genderStr = ToolBox.GetAttributeString(element, "gender", "male").ToLower(); + gender = (genderStr == "male") ? Gender.Male : Gender.Female; + + salary = ToolBox.GetAttributeInt(element, "salary", 1000); + } + + public virtual XElement Save(XElement parentElement) + { + XElement componentElement = new XElement("character"); + + componentElement.Add( + new XAttribute("name", name), + new XAttribute("gender", gender == Gender.Male ? "male" : "female"), + new XAttribute("salary", salary), + new XAttribute("headspriteid", headSpriteId)); + + parentElement.Add(componentElement); + return componentElement; } } } diff --git a/Subsurface/Characters/DelayedEffect.cs b/Subsurface/Characters/DelayedEffect.cs index 1b1646083..8813d017f 100644 --- a/Subsurface/Characters/DelayedEffect.cs +++ b/Subsurface/Characters/DelayedEffect.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using Microsoft.Xna.Framework; +using System.Collections.Generic; using System.Xml.Linq; namespace Subsurface @@ -11,9 +12,9 @@ namespace Subsurface float timer; - private Item item; + Vector2 position; - private Character character; + List targets; public float Timer { @@ -26,14 +27,14 @@ namespace Subsurface delay = ToolBox.GetAttributeFloat(element, "delay", 1.0f); } - public override void Apply(ActionType type, float deltaTime, Item item, Character character = null) + public override void Apply(ActionType type, float deltaTime, Vector2 position, List targets) { if (this.type != type) return; - - this.item = item; - this.character = character; - + timer = delay; + this.position = position; + + this.targets = targets; list.Add(this); } @@ -44,7 +45,7 @@ namespace Subsurface if (timer > 0.0f) return; - base.Apply(1.0f, character, item); + base.Apply(1.0f, position, targets); list.Remove(this); } diff --git a/Subsurface/Characters/Limb.cs b/Subsurface/Characters/Limb.cs index 3292ba9d6..39e57402f 100644 --- a/Subsurface/Characters/Limb.cs +++ b/Subsurface/Characters/Limb.cs @@ -227,7 +227,11 @@ namespace Subsurface string spritePath = subElement.Attribute("texture").Value; if (character.info!=null) + { spritePath = spritePath.Replace("[GENDER]", (character.info.gender == Gender.Female) ? "f" : ""); + spritePath = spritePath.Replace("[HEADID]", character.info.headSpriteId.ToString()); + } + sprite = new Sprite(subElement, "", spritePath); break; diff --git a/Subsurface/Characters/StatusEffect.cs b/Subsurface/Characters/StatusEffect.cs index eea50dc26..2101943e2 100644 --- a/Subsurface/Characters/StatusEffect.cs +++ b/Subsurface/Characters/StatusEffect.cs @@ -9,12 +9,12 @@ namespace Subsurface class StatusEffect { [Flags] - public enum Target + public enum TargetType { This = 1, Parent = 2, Character = 4, Contained = 8, Nearby = 16, UseTarget=32 } - private Target targets; + private TargetType targetTypes; private string[] targetNames; public string[] propertyNames; @@ -30,9 +30,9 @@ namespace Subsurface private Sound sound; - public Target Targets + public TargetType Targets { - get { return targets; } + get { return targetTypes; } } public string[] TargetNames @@ -92,7 +92,7 @@ namespace Subsurface string[] Flags = attribute.Value.Split(','); foreach (string s in Flags) { - targets |= (Target)Enum.Parse(typeof(Target), s, true); + targetTypes |= (TargetType)Enum.Parse(typeof(TargetType), s, true); } break; @@ -143,18 +143,27 @@ namespace Subsurface } - public virtual void Apply(ActionType type, float deltaTime, Item item, Character character = null) - { - if (this.type == type) Apply(deltaTime, character, item); - } + //public virtual void Apply(ActionType type, float deltaTime, Item item, Character character = null) + //{ + // if (this.type == type) Apply(deltaTime, character, item); + //} public virtual void Apply(ActionType type, float deltaTime, Vector2 position, IPropertyObject target) { if (!targetNames.Contains(target.Name)) return; - if (this.type == type) Apply(deltaTime, position, target); + + List targets = new List(); + targets.Add(target); + + if (this.type == type) Apply(deltaTime, position, targets); } - protected virtual void Apply(float deltaTime, Vector2 position, IPropertyObject target) + public virtual void Apply(ActionType type, float deltaTime, Vector2 position, List targets) + { + if (this.type == type) Apply(deltaTime, position, targets); + } + + protected virtual void Apply(float deltaTime, Vector2 position, List targets) { if (explosion != null) explosion.Explode(position); @@ -163,42 +172,45 @@ namespace Subsurface for (int i = 0; i < propertyNames.Count(); i++) { ObjectProperty property; - if (target.ObjectProperties.TryGetValue(propertyNames[i], out property)) + foreach (IPropertyObject target in targets) { - ApplyToProperty(property, propertyEffects[i], deltaTime); + if (targetNames!=null && !targetNames.Contains(target.Name)) continue; + if (!target.ObjectProperties.TryGetValue(propertyNames[i], out property)) continue; + + ApplyToProperty(property, propertyEffects[i], deltaTime); } } } - protected virtual void Apply(float deltaTime, Character character, Item item) - { - if (explosion != null) explosion.Explode(item.SimPosition); + //protected virtual void Apply(float deltaTime, Character character, Item item) + //{ + // if (explosion != null) explosion.Explode(item.SimPosition); - if (sound != null) sound.Play(1.0f, 1000.0f, item.body.FarseerBody); + // if (sound != null) sound.Play(1.0f, 1000.0f, item.body.FarseerBody); - for (int i = 0; i < propertyNames.Count(); i++) - { - ObjectProperty property; + // for (int i = 0; i < propertyNames.Count(); i++) + // { + // ObjectProperty property; - if (character!=null && character.properties.TryGetValue(propertyNames[i], out property)) - { - ApplyToProperty(property, propertyEffects[i], deltaTime); - } + // if (character!=null && character.properties.TryGetValue(propertyNames[i], out property)) + // { + // ApplyToProperty(property, propertyEffects[i], deltaTime); + // } - if (item == null) continue; + // if (item == null) continue; - if (item.properties.TryGetValue(propertyNames[i], out property)) - { - ApplyToProperty(property, propertyEffects[i], deltaTime); - } + // if (item.properties.TryGetValue(propertyNames[i], out property)) + // { + // ApplyToProperty(property, propertyEffects[i], deltaTime); + // } - foreach (ItemComponent ic in item.components) - { - if (!ic.properties.TryGetValue(propertyNames[i], out property)) continue; - ApplyToProperty(property, propertyEffects[i], deltaTime); - } - } - } + // foreach (ItemComponent ic in item.components) + // { + // if (!ic.properties.TryGetValue(propertyNames[i], out property)) continue; + // ApplyToProperty(property, propertyEffects[i], deltaTime); + // } + // } + //} protected void ApplyToProperty(ObjectProperty property, object value, float deltaTime) { diff --git a/Subsurface/Content/Characters/Human/fhead.png b/Subsurface/Content/Characters/Human/fhead1.png similarity index 100% rename from Subsurface/Content/Characters/Human/fhead.png rename to Subsurface/Content/Characters/Human/fhead1.png diff --git a/Subsurface/Content/Characters/Human/fhead2.png b/Subsurface/Content/Characters/Human/fhead2.png new file mode 100644 index 0000000000000000000000000000000000000000..caac6f99a089f5bd1c5d6e49a00ec45b94037e5a GIT binary patch literal 2563 zcmV+e3jFnnP)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ_iAh93RCwC#m}|^sS6#+`YpuQZ-e;f7dpYlA-kIrzPUq5@v9!f$Q!N1rL6N`* zL=6pUBAOTyO(et*BoYn8XhJkGhRcT%_+Uj75SVCNKp zIs3LQen1Kpnamkt^n*{bla+r~vVQCTtgJkH3GY2WPCx&15B_M;gRz!QtEFCbVByI9 z_a1xrp4YtQzSEC={e6?XyzRbw?|#c?PJihmD=Ulj&TiV<+}Q3_CTFIV5b6Y!z&Xnu z2llbho#ppG@Mk}=M8I|QYj1z!D+>Z}o^jewl4kn@cdX1lywIJwMN9MIn_u_pM`f5C zZ_myTZ{6RWPdan2AB^(qi7$TblP{h<_bKPxs&&qJz*%#>Wv>qvh5D6E@}4Nva=8=! z)J&q^8%Ke*wLwnOj-pAJx;^M+ya3uai$_n zI&|k+$*FseyrOUqBqZn)%A_lsi8JDw!ZHh zjYfR`@?7%qQE!)FzmKUalB7u^j?htzkOEf~gjy4XA?0un5rnweMX))6bg0G*^Ro-T zdg`9z@49s1%0teW>7gc-zyl%f)Ivv|-r3x4t*-B|v(uvyC_2rMTMsUhG$NFM@hBr{ zCZxODXeC%Wd^i2AEzEF(h2<_Yhh9xkO*;LZy>wEQJtO?|_61Qwpkx@j{LziA{?gjo z22x4dk)|1G;y{yUIU0cj8bOGxYrqq>+l;q180=mnj5Mulzsuybx&TP|l&Fkf70Ic77>-Y5i-rKl_a{PcJWYriT(b>Qd#T!y#oK zyeZk<-X+i)9attsjRK^t3F0P^j!0S^lnODGLsdB@bEv3+@rpouXlh>jz`ghHjf%g0 z_QkdT-l6M3l~!&#uQ1Ng>+MmL6~l2wQB>4bjkTVlDj8)N<21$AHDxx!mKAn9!scUa zQDQ5LuMD=TsEU$fcigf33$J?!DVQE=Qq+%HFB$Yx^1NnJcx0ea63Vhf2MQr1N@;Wu z5NL@|lG+&R$(TCrWAYqV8*mPsLrclk&7JvAeERcLc|N^;&bu$9+2n;$R-8acjHxLn zHTA^NY&59LoVp5e#!`!le4L?!2tS!1(iBymr`ZOfzX@Z+iWM)W%E? zmG$@PahCnPMVyGj2;mJy?TA%CQPd0vBVw&7qX>pr=VMe^6RU`_tO)Xg&7Cb? zxO|1f~V#uPhQTatyW8w- zYy>}ZHc}cpT?8_D+B5v9BNfhbO-Jc%EiA5nX~GOwkQq;mx*b1LJY#3GR&VA>F!SG5c zJkiZ$^eB#A9@pvc>Va0=KM*a>K67P@x~kZjOlWnQBuPkKRt%K{@6dq)p%GePwInSj zeCyjU@!aa>BWG7PKUmfd-D)6%o4C=-qIh|H{Oi4Em8>rDUm`V@-dZ{FsXbw&dV@v=8Lh%3qc+ZZX&w;kUn?%@3Obv zd-Bs|Cf^wax_Ny6zB&#LdWQ^$-idJymtR_=Kb}z3hRO;SQFL?w9+vmbkzQPXWN&v5 ztrQ-C?lyliD1iRn_L)W?Hl*}-3MG^iu5N{~>*`RoltN3znakg0@7gxoqm0{@=D5u+ zve<56>Uto8$10k)!|k-uJ)n9e?E*dWq$B~=7p3F0p4Q~K62hx z#t37b1}}jckFIO8{#PISYv-$yX(exDk_+_9pH;y(zsKYS-dQJ*p$dffUd>5Fsda?+ z%8o}V^K-LPL)}oPWble&^EDgS4n z{>z)$bD7t_BH(R-R1ZZ$Js9htlbgB_QoMk7e_B@MXWIyFR^oaudH-9I{2$c+L*1zU ZV*oyP($4%{VEq69002ovPDHLkV1gFW@gx8M literal 0 HcmV?d00001 diff --git a/Subsurface/Content/Characters/Human/head.png b/Subsurface/Content/Characters/Human/head1.png similarity index 100% rename from Subsurface/Content/Characters/Human/head.png rename to Subsurface/Content/Characters/Human/head1.png diff --git a/Subsurface/Content/Characters/Human/head3.png b/Subsurface/Content/Characters/Human/head3.png new file mode 100644 index 0000000000000000000000000000000000000000..58e8b9c86231ea9417627d41e31bc4e92c6fd36f GIT binary patch literal 2266 zcmV<02qpK4P)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ^U`a$lRCwC#m`QA2R~5&9_rCjvZyx;lvt!3joWxF=G$u(yr?j-R(3TF0DzQKa zfdr@$f&~&~&6+(3gy@D9w4gGSN>v4jMjb+%Dns2QO`Jdm$BE-_{@(oVWf6*mkV{&BlZfS}A*}))+lq7-=59bouh4$pt`ss`3&pfkv z+w6}W*X4f|*G)m`e=TB3Nw?dbKYsYNpC;kpuEEf!SSVmAi!@0HuKM)49qQ!@TSmud zPEIp2(#UTd8{2#8?AafkJGroW%btC|%(CnQ-zRRSC7e5R8r!z%v{suhJo~Fd!Js#X z0HY1cRv4XONsFB4BD07++h*9a?+)DB2v`znS&(VYTwFRKt0Q||$H|N_%-ynU?M^kv zCy1lidFlDz{%p``&n0O>rZrMpq(h%HO_7$QUMbNi=h1*pV$wkmV@ZTmDBEUca$>iy z+()fk;SYR(8R};9=&e@|eeKl3@qnlY3O6n z2uqP7vE3X=Ccby_+Nl>X#@zqNV{3;>;<)hcu_NCN!hoS4U@JvtAPORqEJYwN#t;dO zG=?izud$&%Lb;d+lOcq}avYLgmqa@I7f&us24Q$s!rt&S9I z5=yNvr&2_9I2_Pwbr2YOgCTJe^PSJ$MLlS-qqvQi&t1ijBV1eJ*b2vW2;(7SifXw= z5=FGzZM3DRX!$MUc)uYYK%TZZYNb@qaMCsYyEu4>h&+ ztLxdmYNN4e+lp$jL>z_8PHbf7%oJJ*Oq>wLF&l2*j6#s53Bz6&FPB5PIb3D4e|!_u ztE*HCdFnZrvRl}2_RLvpa%wtVGt}lS+m5?#ZmHAmOcZhs1sl>dpf&6I$tZ zmxy&n7={R8u#`eb3!P=)78oC$?QPlEK5-=)hL&$K*n&`C5(pj+AH|o7A6hxEQJmN#-#Owb+rU( zNoKci{}bj$z(}ovWjmy{!@}7Gj=udS!yv@AJ&MI5UcQL39gNY$aY(P*;>z*`md`Ju z!h~|QjvWNM*3}YRH^fob~uidFMNvTw87k2Hw_4Tcjqm=R<%2MRLJo$VP z>3PHmuJ?KjqL_{!5TqH>Qa6sDIA*m!WT`jgydN@XZ2Za0LysL;ms7>OhjLsqziaNW zS(Xn@O->T026Tc_iZFxa8p^T|mW9+Q)j|$eS)@j@w7g7`WHhT~cFga6Q9Isn zT~M`p9m{suJT<+n>EhT9T4d-nLpTm7o2x5ViK3YHppWa=*izDR6wPXhPJckZ7a~)` z$cD-H_T6>&E2U~}eaB3(Ttz6G(a}bcc!DrV5NU=H5}_2z5)|?_S5{WA+b-q2O{tit zCj`S`pGq;uV-MVe6gIAXSnkK|)g0ftSUXG#TkaHBS5-2HH?fSHOLpC-eYPAwklH!Md=fOK}qgJkQZMA&~ z+g&G=gk6GysSZeh-zuciwE1|VS z3MiGzY@eIq-Id;zBpR*{>V26s*=@82OJRfsQXp-cLZOVb1eHn+*K;vKMt45+_*4Bb zx&GRrSDrd{^w`0i>oFMgc;KGfmmdDoR~HfTqk+;o18JcFlWEc+EXPRQJ z$k@dAE0(2yv2*7Rw3dIq``-J%a^>>HTP;j!|L320X6yFdoit588mJ6;q#O8;_)$W= zTEJjP(h!|y#8E^T#q|3FuZhHR|;m zA7(fw)-uUE_tzK4f-ss7`<+kK8Y4 o7-QJ9b?&2s`ec&#anU~q0Ib0L)O~Uupa1{>07*qoM6N<$f*i3{ssI20 literal 0 HcmV?d00001 diff --git a/Subsurface/Content/Characters/Human/head4.png b/Subsurface/Content/Characters/Human/head4.png new file mode 100644 index 0000000000000000000000000000000000000000..65e524fedd5f2d0a5728f63d551c56992f3e7299 GIT binary patch literal 2143 zcmV-l2%z_gP)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ@DoFHYOSeaHE1`p(3J~ z1auP=K?E_Vs1b1^LR=_umF$Az5E0{miXusj#EzOWCU&~ItE;+exc8sV=pq}53R2aA z3*YrQoQLl_e7xT)a?bp(N%B7^{hu7VUU+K$wH8GgcJ@AC8Q+9aJ?-!yS=w5 zwYD@(MM@bZK_sZV8lx4?CydcU=QeNg-TDLl(G9niy)$>^(1qwKT)RixTsat&(uTdQ z=kET~-`2h=MU*Ldrn@yE27F2gDN!;Jd?dw$lmhQONkC4L_R`r8SUdVlirp8xb}t5B z6GOXysFX80ZM`EmPv1Y8Y|}3dDFl>Cq@2(>5rU^n5v2`UDTDw7NCd6-SYz3`^wcM{ zw7(Ndd{38sdJD()4>cIfv3=$2Cydd|k4Mzilq{fa9X=(<86#m>ShR%2o@UT9xER@} z5>qMAN)bco4_B@~(H|dXI9}oS{AmAB13mLM|5NNlc6p}JSZM1uuxBW&#%j$gR|Ys2aXyiA#2AIr3WOvjhxg5?9BM0Lg^tYu zK6NnQ^0D0>XkIkVF(o3QcA(nxQA4rWJC&sE-Wb~j1fo!-f%lzgX)5y7n+Di({nH zn6hNMYIx$ekF&8=ar)#kDf8EF|LAPM4xx8|IVFwSGev*bcGU=%sRf+5=`_vGI&05w zG8_z89QGKN1q*W{thKlp*{xdE{`@>F9%K5<6Wp*gppM-Mj=X_mD@!cT_4f}Id^5GZ z(L>u?=kJb5aPv(!a?jhY+x==jB(Pk%vB(An(6YcIb3jtx0Wgalo5SkJ#L}$YgiIcwxk?Cr&cHW{YRm z{zwRkUfILPz{0{jP17;08cv>==g`U_x}cc1=kK{8=l=P0>Jz}uzD7dy9xILO_xgF% z7wl|bAhaz{Klx`aY+RLW5KS=N#U5ATkJnu@(gQ z7?DDeQ{uK)pJZ;fkFxq)*EO^{AKarK8Jl+F+*x|P8D@Gz5&>7&5CgTVNr1H$tu;w2 zqW6Th;mUMEzi;VWpccA{A&h*}BJ)*%Qn~v>Gu^|tQ)FC3NeH1Pg+SA`gcN8yjaC9{ zEjcE9&e;Aeh4VD+6Hf8VNP(G)%7!y8DnNC345)mCad!nmpI!{Jo ztVYTTsT3}PkecCmnV3KpG0MT>3(}UnXygwFrIm5fCKp1q-q*zFu%^JrNKBAYr0p6e z(}a*YBE&CJW}|aq>M-YeD=d%d-PZP zO-#goL$lx9|B)LK=? - + @@ -8,7 +8,7 @@ - + diff --git a/Subsurface/Content/Items/Clothes/captainhat.png b/Subsurface/Content/Items/Clothes/captainhat.png new file mode 100644 index 0000000000000000000000000000000000000000..732da7578e3344f70a6099ab983a7486aefa5b7d GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWNq$1fP z$d`ekN|k}3p_zf<=YJsml7XSrfPvvv0t1893yD}dYaZ8^hMgb9S(k**`B*nUWpDJVkbA#h73R1fzWk%G^L^Wwx($mR;vZ;B#h=~z zqn@=hjeExeDT6Cn^CFpMGTimo30S#4^U4~_l?>^VZs=VwU&yuMK+i2Uh8M*N5pT85 RR0Dm*;OXk;vd$@?2>>YpdgcHC literal 0 HcmV?d00001 diff --git a/Subsurface/Content/Items/Clothes/clothes.xml b/Subsurface/Content/Items/Clothes/clothes.xml new file mode 100644 index 000000000..0dfb9fcf3 --- /dev/null +++ b/Subsurface/Content/Items/Clothes/clothes.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/Subsurface/Content/Items/Diving/divinggear.xml b/Subsurface/Content/Items/Diving/divinggear.xml index 79cdf2cfb..0c5b41dc6 100644 --- a/Subsurface/Content/Items/Diving/divinggear.xml +++ b/Subsurface/Content/Items/Diving/divinggear.xml @@ -11,8 +11,8 @@ - - + + diff --git a/Subsurface/DebugConsole.cs b/Subsurface/DebugConsole.cs index 1ace775a9..a9fdfd4d3 100644 --- a/Subsurface/DebugConsole.cs +++ b/Subsurface/DebugConsole.cs @@ -209,12 +209,20 @@ namespace Subsurface Game1.LobbyScreen.Select(); break; case "savemap": + if (commands.Length < 2) break; Map.Loaded.SaveAs("Content/SavedMaps/" + commands[1]); NewMessage("map saved", Color.Green); break; case "loadmap": + if (commands.Length < 2) break; Map.Load("Content/SavedMaps/" + commands[1]); break; + case "savegame": + SaveUtil.SaveGame("Content/Data/test.save"); + break; + case "loadgame": + SaveUtil.LoadGame("Content/Data/test.save"); + break; case "messagebox": if (commands.Length < 3) break; new GUIMessageBox(commands[1], commands[2]); diff --git a/Subsurface/GUI/GUI.cs b/Subsurface/GUI/GUI.cs index 727f32001..f53eedb3c 100644 --- a/Subsurface/GUI/GUI.cs +++ b/Subsurface/GUI/GUI.cs @@ -269,7 +269,7 @@ namespace Subsurface // new Vector2(10, 30), Color.White); - if (Character.Controlled != null) Character.Controlled.DrawHud(spriteBatch, cam); + if (Character.Controlled != null && cam!=null) Character.Controlled.DrawHud(spriteBatch, cam); DrawMessages(spriteBatch, (float)deltaTime); diff --git a/Subsurface/Game1.cs b/Subsurface/Game1.cs index 9510a5c1f..233a22910 100644 --- a/Subsurface/Game1.cs +++ b/Subsurface/Game1.cs @@ -103,7 +103,6 @@ namespace Subsurface /// protected override void Initialize() { - // TODO: Add your initialization logic here base.Initialize(); particleManager = new ParticleManager("Content/Particles/prefabs.xml", Cam); diff --git a/Subsurface/GameSession/CrewManager.cs b/Subsurface/GameSession/CrewManager.cs index 78daf7c79..20ab779df 100644 --- a/Subsurface/GameSession/CrewManager.cs +++ b/Subsurface/GameSession/CrewManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using System.Xml.Linq; namespace Subsurface { @@ -25,7 +26,7 @@ namespace Subsurface set { money = (int)Math.Max(value, 0.0f); } } - public CrewManager(GameSession session) + public CrewManager() { characters = new List(); characterInfos = new List(); @@ -39,6 +40,19 @@ namespace Subsurface money = 10000; } + public CrewManager(XElement element) + : this() + { + money = ToolBox.GetAttributeInt(element, "money", 0); + + foreach (XElement subElement in element.Elements()) + { + if (subElement.Name.ToString().ToLower()!="character") continue; + + characterInfos.Add(new CharacterInfo(subElement)); + } + } + private string CreateSaveFile(string mapName) { string path = "Content/Data/Saves/"; @@ -89,7 +103,7 @@ namespace Subsurface GUITextBlock textBlock = new GUITextBlock( new Rectangle(40,0,0,25), name, - Color.Transparent, Color.Black, + Color.Transparent, Color.White, Alignment.Left, Alignment.Left, frame); @@ -98,6 +112,11 @@ namespace Subsurface new GUIImage(new Rectangle(-10,-10,0,0), character.animController.limbs[0].sprite, Alignment.Left, frame); } + public void Update(float deltaTime) + { + guiFrame.Update(deltaTime); + } + public void KillCharacter(Character killedCharacter) { GUIComponent characterBlock = listBox.GetChild(killedCharacter) as GUIComponent; @@ -138,5 +157,27 @@ namespace Subsurface { guiFrame.Draw(spriteBatch); } + + public void Save(string filePath) + { + XDocument doc = new XDocument( + new XElement((XName)"Crew")); + + doc.Root.Add(new XAttribute("money", money)); + + foreach (CharacterInfo ci in characterInfos) + { + ci.Save(doc.Root); + } + + try + { + doc.Save(filePath); + } + catch + { + DebugConsole.ThrowError("Saving crewmanager to ''" + filePath + "'' failed!"); + } + } } } diff --git a/Subsurface/GameSession/GameSession.cs b/Subsurface/GameSession/GameSession.cs index bcb18bd55..b2bf0403d 100644 --- a/Subsurface/GameSession/GameSession.cs +++ b/Subsurface/GameSession/GameSession.cs @@ -6,6 +6,7 @@ using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using System.Text; using System.Collections.Generic; +using System.Xml.Linq; namespace Subsurface { @@ -20,6 +21,8 @@ namespace Subsurface public readonly GameMode gameMode; + private GUIFrame guiRoot; + private GUIListBox chatBox; private GUITextBox textBox; @@ -27,57 +30,76 @@ namespace Subsurface private GUIButton endShiftButton; - string saveFile; - + Map selectedMap; + private int day; - public string SaveFile - { - get { return saveFile; } - } + //public string SaveFile + //{ + // get { return saveFile; } + //} public int Day { get { return day; } } - public GameSession(string selectedMapFile, bool save, TimeSpan gameDuration, GameMode gameMode = null) + public GameSession(Map selectedMap, TimeSpan gameDuration, GameMode gameMode = null) { taskManager = new TaskManager(this); - crewManager = new CrewManager(this); + crewManager = new CrewManager(); hireManager = new HireManager(); hireManager.GenerateCharacters("Content/Characters/Human/human.xml", 10); + guiRoot = new GUIFrame(new Rectangle(0,0,Game1.GraphicsWidth,Game1.GraphicsWidth), Color.Transparent); + int width = 350, height = 100; - chatBox = new GUIListBox(new Rectangle( - Game1.GraphicsWidth - (int)GUI.style.smallPadding.X - width, - Game1.GraphicsHeight - (int)GUI.style.smallPadding.W*2 - 25 - height, - width, height), - Color.White * 0.5f); + if (Game1.Client!=null || Game1.Server!=null) + { + chatBox = new GUIListBox(new Rectangle( + Game1.GraphicsWidth - (int)GUI.style.smallPadding.X - width, + Game1.GraphicsHeight - (int)GUI.style.smallPadding.W*2 - 25 - height, + width, height), + Color.White * 0.5f, guiRoot); - endShiftButton = new GUIButton(new Rectangle(Game1.GraphicsWidth - 240, 20, 100, 25), "End shift", Color.White, Alignment.CenterX, null); - endShiftButton.OnClicked = EndShift; + textBox = new GUITextBox( + new Rectangle(chatBox.Rect.X, chatBox.Rect.Y + chatBox.Rect.Height + (int)GUI.style.smallPadding.W, chatBox.Rect.Width, 25), + Color.White * 0.5f, Color.Black, Alignment.Bottom, Alignment.Left, guiRoot); + textBox.OnEnter = EnterChatMessage; + } - timerBar = new GUIProgressBar(new Rectangle(Game1.GraphicsWidth - 120, 20, 100, 25), Color.Gold, 0.0f, null); + if (Game1.Client==null) + { + endShiftButton = new GUIButton(new Rectangle(Game1.GraphicsWidth - 240, 20, 100, 25), "End shift", Color.White, Alignment.Left | Alignment.Top, guiRoot); + endShiftButton.OnClicked = EndShift; + } + + timerBar = new GUIProgressBar(new Rectangle(Game1.GraphicsWidth - 120, 20, 100, 25), Color.Gold, 0.0f, guiRoot); - textBox = new GUITextBox( - new Rectangle(chatBox.Rect.X, chatBox.Rect.Y + chatBox.Rect.Height + (int)GUI.style.smallPadding.W, chatBox.Rect.Width, 25), - Color.White * 0.5f, Color.Black, Alignment.Bottom, Alignment.Left); - textBox.OnEnter = EnterChatMessage; this.gameMode = gameMode; if (this.gameMode != null) this.gameMode.Start(Game1.NetLobbyScreen.GameDuration); startTime = DateTime.Now; - endTime = startTime + gameDuration; + endTime = startTime + gameDuration; - if (!save) return; - - CreateSaveFile(selectedMapFile); - - day = 1; + this.selectedMap = selectedMap; + //if (!save) return; + + //CreateSaveFile(selectedMapFile); + + day = 1; + } + + public GameSession(string filePath) + : this(null, new TimeSpan(0,0,0,0)) + { + XDocument doc = ToolBox.TryLoadXml(filePath); + if (doc == null) return; + + day = ToolBox.GetAttributeInt(doc.Root,"day",1); } public bool TryHireCharacter(CharacterInfo characterInfo) @@ -101,6 +123,8 @@ namespace Subsurface { if (crewManager.characterInfos.Count == 0) return; + if (Map.Loaded!=selectedMap) selectedMap.Load(); + crewManager.StartShift(); taskManager.StartShift(scriptedEventCount); } @@ -135,9 +159,9 @@ namespace Subsurface new GUIMessageBox("Day #" + day + " is over!\n", sb.ToString()); - if (saveFile == null) return false; + //if (saveFile == null) return false; - Map.Loaded.SaveAs(saveFile); + //Map.Loaded.SaveAs(saveFile); crewManager.EndShift(); @@ -146,6 +170,11 @@ namespace Subsurface day++; } + for (int i = Character.characterList.Count - 1; i >= 0; i--) + { + Character.characterList.RemoveAt(i); + } + taskManager.EndShift(); return true; @@ -153,33 +182,33 @@ namespace Subsurface private void CreateSaveFile(string mapName) { - string path = "Content/Data/Saves/"; + //string path = "Content/Data/Saves/"; - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } + //if (!Directory.Exists(path)) + //{ + // Directory.CreateDirectory(path); + //} - string name = Path.GetFileNameWithoutExtension(mapName); - string extension = Path.GetExtension(mapName); + //string name = Path.GetFileNameWithoutExtension(mapName); + //string extension = Path.GetExtension(mapName); - int i = 0; - while (File.Exists(path + name + i + extension)) - { - i++; - } + //int i = 0; + //while (File.Exists(path + name + i + extension)) + //{ + // i++; + //} - saveFile = path + name + i+extension; + //saveFile = path + name + i+extension; - try - { - File.Copy(mapName, saveFile); - } - catch (Exception e) - { - DebugConsole.ThrowError("Copying map file ''" + mapName + "'' to ''" + saveFile + "'' failed", e); - } + //try + //{ + // File.Copy(mapName, saveFile); + //} + //catch (Exception e) + //{ + // DebugConsole.ThrowError("Copying map file ''" + mapName + "'' to ''" + saveFile + "'' failed", e); + //} } public bool EnterChatMessage(GUITextBox textBox, string message) @@ -218,11 +247,14 @@ namespace Subsurface public void Update(float deltaTime) { taskManager.Update(deltaTime); - endShiftButton.Enabled = !taskManager.CriticalTasks; + if (endShiftButton!=null) endShiftButton.Enabled = !taskManager.CriticalTasks; - endShiftButton.Update(deltaTime); + + guiRoot.Update(deltaTime); + crewManager.Update(deltaTime); + //endShiftButton.Update(deltaTime); - textBox.Update(deltaTime); + //textBox.Update(deltaTime); if (gameMode != null) gameMode.Update(); @@ -246,15 +278,33 @@ namespace Subsurface public void Draw(SpriteBatch spriteBatch) { + guiRoot.Draw(spriteBatch); crewManager.Draw(spriteBatch); taskManager.Draw(spriteBatch); - chatBox.Draw(spriteBatch); - textBox.Draw(spriteBatch); + //chatBox.Draw(spriteBatch); + //textBox.Draw(spriteBatch); - timerBar.Draw(spriteBatch); + //timerBar.Draw(spriteBatch); - if (Game1.Client == null) endShiftButton.Draw(spriteBatch); + //if (Game1.Client == null) endShiftButton.Draw(spriteBatch); + } + + public void Save(string filePath) + { + XDocument doc = new XDocument( + new XElement((XName)"Gamesession")); + + doc.Root.Add(new XAttribute("day", day)); + + try + { + doc.Save(filePath); + } + catch + { + DebugConsole.ThrowError("Saving gamesession to ''" + filePath + "'' failed!"); + } } } } diff --git a/Subsurface/Items/Components/Container.cs b/Subsurface/Items/Components/Container.cs index 63c6a12db..288470e32 100644 --- a/Subsurface/Items/Components/Container.cs +++ b/Subsurface/Items/Components/Container.cs @@ -115,47 +115,13 @@ namespace Subsurface.Items.Components foreach (StatusEffect effect in ri.statusEffects) { - if (effect.Targets.HasFlag(StatusEffect.Target.This)) effect.Apply(ActionType.OnContaining, deltaTime, item); - if (effect.Targets.HasFlag(StatusEffect.Target.Contained)) effect.Apply(ActionType.OnContaining, deltaTime, contained); + if (effect.Targets.HasFlag(StatusEffect.TargetType.This)) effect.Apply(ActionType.OnContaining, deltaTime, item.SimPosition, item.AllPropertyObjects); + if (effect.Targets.HasFlag(StatusEffect.TargetType.Contained)) effect.Apply(ActionType.OnContaining, deltaTime, item.SimPosition, contained.AllPropertyObjects); } contained.ApplyStatusEffects(ActionType.OnContained, deltaTime); } - //if (hideItems) return; - - //Vector2 transformedItemPos; - //Vector2 transformedItemInterval = itemInterval; - ////float transformedItemRotation = itemRotation; - //if (item.body==null) - //{ - // transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y); - // transformedItemPos = ConvertUnits.ToSimUnits(transformedItemPos) + itemPos; - //} - //else - //{ - // Matrix transform = Matrix.CreateRotationZ(item.body.Rotation); - - // transformedItemPos = item.body.Position + Vector2.Transform(itemPos, transform); - // transformedItemInterval = Vector2.Transform(transformedItemInterval, transform); - // //transformedItemRotation += item.body.Rotation; - //} - - //foreach (Item containedItem in inventory.items) - //{ - // if (containedItem == null) continue; - - // Vector2 itemDist = (transformedItemPos - containedItem.body.Position); - // Vector2 force = (itemDist - containedItem.body.LinearVelocity * 0.1f) * containedItem.body.Mass * 60.0f; - - // containedItem.body.ApplyForce(force); - - // containedItem.body.SmoothRotate(itemRotation); - - // transformedItemPos += transformedItemInterval; - //} - - } public override void Draw(SpriteBatch spriteBatch) diff --git a/Subsurface/Items/Components/Door.cs b/Subsurface/Items/Components/Door.cs index 69d84c23a..aa6bd1cbd 100644 --- a/Subsurface/Items/Components/Door.cs +++ b/Subsurface/Items/Components/Door.cs @@ -233,9 +233,12 @@ namespace Subsurface.Items.Components public override void Update(float deltaTime, Camera cam) { - OpenState += deltaTime * ((isOpen) ? 3.0f : -3.0f); + if (!isStuck) + { + OpenState += deltaTime * ((isOpen) ? 3.0f : -3.0f); + LinkedGap.Open = openState; + } - LinkedGap.Open = openState; item.SendSignal((isOpen) ? "1" : "0", "state_out"); } @@ -309,8 +312,6 @@ namespace Subsurface.Items.Components public override void ReceiveSignal(string signal, Connection connection, Item sender) { - if (isStuck) return; - if (connection.name=="toggle") { isOpen = !isOpen; diff --git a/Subsurface/Items/Components/ItemComponent.cs b/Subsurface/Items/Components/ItemComponent.cs index 9e79166f7..5e7763ff8 100644 --- a/Subsurface/Items/Components/ItemComponent.cs +++ b/Subsurface/Items/Components/ItemComponent.cs @@ -291,7 +291,13 @@ namespace Subsurface return false; } - public virtual void Remove() { } + public virtual void Remove() + { + if (loopingSound!=null) + { + Sounds.SoundManager.Stop(loopingSoundIndex); + } + } public bool HasRequiredContainedItems(bool addMessage) { diff --git a/Subsurface/Items/Components/RepairTool.cs b/Subsurface/Items/Components/RepairTool.cs index 37049cb64..9571498ba 100644 --- a/Subsurface/Items/Components/RepairTool.cs +++ b/Subsurface/Items/Components/RepairTool.cs @@ -147,8 +147,8 @@ namespace Subsurface.Items.Components foreach (StatusEffect effect in statusEffects) { - if (Array.IndexOf(effect.TargetNames, targetItem.Name) == -1) continue; - effect.Apply(ActionType.OnUse, deltaTime, targetItem); + //if (Array.IndexOf(effect.TargetNames, targetItem.Name) == -1) continue; + effect.Apply(ActionType.OnUse, deltaTime, item.SimPosition, targetItem.AllPropertyObjects); //targetItem.ApplyStatusEffect(effect, ActionType.OnUse, deltaTime); } //ApplyStatusEffects(ActionType.OnUse, 1.0f, null, targ); diff --git a/Subsurface/Items/Components/Wearable.cs b/Subsurface/Items/Components/Wearable.cs index ae3bb018f..db693fd27 100644 --- a/Subsurface/Items/Components/Wearable.cs +++ b/Subsurface/Items/Components/Wearable.cs @@ -115,22 +115,14 @@ namespace Subsurface.Items.Components Item[] containedItems = item.ContainedItems; + ApplyStatusEffects(ActionType.OnWearing, deltaTime, picker); - for (int i = 0; i < limb.Length; i++) + if (containedItems == null) return; + for (int j = 0; j AllPropertyObjects + { + get + { + List pobjects = new List(); + pobjects.Add(this); + foreach (ItemComponent ic in components) + { + pobjects.Add(ic); + } + return pobjects; + } + } + List highlightText; public List HighlightText @@ -334,9 +348,11 @@ namespace Subsurface } } + List targets = new List(); + if (containedItems!=null) { - if (effect.Targets.HasFlag(StatusEffect.Target.Contained)) + if (effect.Targets.HasFlag(StatusEffect.TargetType.Contained)) { foreach (Item containedItem in containedItems) { @@ -344,7 +360,8 @@ namespace Subsurface if (effect.TargetNames != null && !effect.TargetNames.Contains(containedItem.Name)) continue; hasTargets = true; - effect.Apply(type, deltaTime, containedItem); + targets.Add(containedItem); + //effect.Apply(type, deltaTime, containedItem); //containedItem.ApplyStatusEffect(effect, type, deltaTime, containedItem); } } @@ -353,19 +370,27 @@ namespace Subsurface if (hasTargets) { - if (effect.Targets.HasFlag(StatusEffect.Target.This)) - effect.Apply(type, deltaTime, this); + if (effect.Targets.HasFlag(StatusEffect.TargetType.This)) + { + foreach (var pobject in AllPropertyObjects) + { + targets.Add(pobject); + } + } + //effect.Apply(type, deltaTime, this); //ApplyStatusEffect(effect, type, deltaTime, this); - if (effect.Targets.HasFlag(StatusEffect.Target.Character)) - effect.Apply(type, deltaTime, null, character); + if (effect.Targets.HasFlag(StatusEffect.TargetType.Character)) targets.Add(character); + //effect.Apply(type, deltaTime, null, character); //ApplyStatusEffect(effect, type, deltaTime, null, character, limb); - if (container != null && effect.Targets.HasFlag(StatusEffect.Target.Parent)) - { - effect.Apply(type, deltaTime, container); - //container.ApplyStatusEffect(effect, type, deltaTime, container); - } + if (container != null && effect.Targets.HasFlag(StatusEffect.TargetType.Parent)) targets.Add(container); + //{ + // effect.Apply(type, deltaTime, container); + // //container.ApplyStatusEffect(effect, type, deltaTime, container); + //} + + effect.Apply(type, deltaTime, SimPosition, targets); } } diff --git a/Subsurface/Map/Map.cs b/Subsurface/Map/Map.cs index e5d28e9cb..0ea5ad66f 100644 --- a/Subsurface/Map/Map.cs +++ b/Subsurface/Map/Map.cs @@ -62,6 +62,8 @@ namespace Subsurface { get { + if (mapHash != null) return mapHash; + XDocument doc = OpenDoc(filePath); mapHash = new MapHash(doc); @@ -286,8 +288,7 @@ namespace Subsurface try { - //string docString = doc.ToString(); - ToolBox.CompressStringToFile(filePath, doc.ToString()); + SaveUtil.CompressStringToFile(filePath, doc.ToString()); } catch { @@ -388,7 +389,7 @@ namespace Subsurface if (extension == ".gz") { - Stream stream = ToolBox.DecompressFiletoStream(file); + Stream stream = SaveUtil.DecompressFiletoStream(file); if (stream == null) { DebugConsole.ThrowError("Loading map ''" + file + "'' failed!"); @@ -504,7 +505,7 @@ namespace Subsurface public static void Unload() { - if (loaded==null)return; + if (loaded == null) return; loaded.Clear(); loaded = null; } diff --git a/Subsurface/Networking/GameClient.cs b/Subsurface/Networking/GameClient.cs index 2a2081060..eae49a78e 100644 --- a/Subsurface/Networking/GameClient.cs +++ b/Subsurface/Networking/GameClient.cs @@ -240,7 +240,7 @@ namespace Subsurface.Networking TimeSpan duration = new TimeSpan(0,(int)durationMinutes,0); //int gameModeIndex = inc.ReadInt32(); - Game1.GameSession = new GameSession("", false, duration); + Game1.GameSession = new GameSession(Map.Loaded, duration); Game1.GameSession.StartShift(1); myCharacter = ReadCharacterData(inc); diff --git a/Subsurface/Networking/GameServer.cs b/Subsurface/Networking/GameServer.cs index fe9dd925c..8704f091b 100644 --- a/Subsurface/Networking/GameServer.cs +++ b/Subsurface/Networking/GameServer.cs @@ -273,9 +273,9 @@ namespace Subsurface.Networking Map selectedMap = Game1.NetLobbyScreen.SelectedMap as Map; - selectedMap.Load(); + //selectedMap.Load(); - Game1.GameSession = new GameSession("", false, Game1.NetLobbyScreen.GameDuration, Game1.NetLobbyScreen.SelectedMode); + Game1.GameSession = new GameSession(selectedMap, Game1.NetLobbyScreen.GameDuration, Game1.NetLobbyScreen.SelectedMode); Game1.GameSession.StartShift(1); //EventManager.SelectEvent(Game1.netLobbyScreen.SelectedEvent); diff --git a/Subsurface/SaveUtil.cs b/Subsurface/SaveUtil.cs new file mode 100644 index 000000000..81678ab23 --- /dev/null +++ b/Subsurface/SaveUtil.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; + +namespace Subsurface +{ + class SaveUtil + { + public delegate void ProgressDelegate(string sMessage); + + public static void SaveGame(string directory) + { + if (Directory.Exists(directory)) + { + Directory.Delete(directory, true); + } + + Directory.CreateDirectory(directory); + + Map.Loaded.SaveAs(directory+"\\map.gz"); + + Game1.GameSession.crewManager.Save(directory+"\\crew.xml"); + + CompressDirectory(directory, directory+".save", null); + + Directory.Delete(directory, true); + } + + public static void LoadGame(string filePath) + { + DecompressToDirectory(filePath+".save", Path.GetDirectoryName(filePath)+"\\temp", null); + + Map.Load(Path.GetDirectoryName(filePath) + "\\temp\\map.gz"); + Game1.GameSession = new GameSession(Path.GetDirectoryName(filePath) + "\\temp\\map.gz"); + } + + public static string CreateSavePath(string saveFolder, string fileName="save") + { + if (!Directory.Exists(saveFolder)) + { + DebugConsole.ThrowError("Save folder ''"+saveFolder+"'' not found. Created new folder"); + Directory.CreateDirectory(saveFolder); + } + + string extension = ".save"; + + int i = 0; + while (File.Exists(saveFolder + fileName + i + extension)) + { + i++; + } + + return saveFolder + fileName + i + extension; + } + + public static void CompressStringToFile(string fileName, string value) + { + // A. + // Write string to temporary file. + string temp = Path.GetTempFileName(); + File.WriteAllText(temp, value); + + // B. + // Read file into byte array buffer. + byte[] b; + using (FileStream f = new FileStream(temp, FileMode.Open)) + { + b = new byte[f.Length]; + f.Read(b, 0, (int)f.Length); + } + + // C. + // Use GZipStream to write compressed bytes to target file. + using (FileStream f2 = new FileStream(fileName, FileMode.Create)) + using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false)) + { + gz.Write(b, 0, b.Length); + } + } + + public static Stream DecompressFiletoStream(string fileName) + { + if (!File.Exists(fileName)) + { + DebugConsole.ThrowError("File ''"+fileName+" doesn't exist!"); + return null; + } + + using (FileStream originalFileStream = new FileStream(fileName, FileMode.Open)) + { + MemoryStream decompressedFileStream = new MemoryStream(); + + using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress)) + { + decompressionStream.CopyTo(decompressedFileStream); + return decompressedFileStream; + } + } + } + + public static void CompressFile(string sDir, string sRelativePath, GZipStream zipStream) + { + //Compress file name + char[] chars = sRelativePath.ToCharArray(); + zipStream.Write(BitConverter.GetBytes(chars.Length), 0, sizeof(int)); + foreach (char c in chars) + zipStream.Write(BitConverter.GetBytes(c), 0, sizeof(char)); + + //Compress file content + byte[] bytes = File.ReadAllBytes(Path.Combine(sDir, sRelativePath)); + zipStream.Write(BitConverter.GetBytes(bytes.Length), 0, sizeof(int)); + zipStream.Write(bytes, 0, bytes.Length); + } + + public static bool DecompressFile(string sDir, GZipStream zipStream, ProgressDelegate progress) + { + //Decompress file name + byte[] bytes = new byte[sizeof(int)]; + int Readed = zipStream.Read(bytes, 0, sizeof(int)); + if (Readed < sizeof(int)) + return false; + + int iNameLen = BitConverter.ToInt32(bytes, 0); + bytes = new byte[sizeof(char)]; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < iNameLen; i++) + { + zipStream.Read(bytes, 0, sizeof(char)); + char c = BitConverter.ToChar(bytes, 0); + sb.Append(c); + } + string sFileName = sb.ToString(); + if (progress != null) + progress(sFileName); + + //Decompress file content + bytes = new byte[sizeof(int)]; + zipStream.Read(bytes, 0, sizeof(int)); + int iFileLen = BitConverter.ToInt32(bytes, 0); + + bytes = new byte[iFileLen]; + zipStream.Read(bytes, 0, bytes.Length); + + string sFilePath = Path.Combine(sDir, sFileName); + string sFinalDir = Path.GetDirectoryName(sFilePath); + if (!Directory.Exists(sFinalDir)) + Directory.CreateDirectory(sFinalDir); + + using (FileStream outFile = new FileStream(sFilePath, FileMode.Create, FileAccess.Write, FileShare.None)) + outFile.Write(bytes, 0, iFileLen); + + return true; + } + + public static void CompressDirectory(string sInDir, string sOutFile, ProgressDelegate progress) + { + string[] sFiles = Directory.GetFiles(sInDir, "*.*", SearchOption.AllDirectories); + int iDirLen = sInDir[sInDir.Length - 1] == Path.DirectorySeparatorChar ? sInDir.Length : sInDir.Length + 1; + + using (FileStream outFile = new FileStream(sOutFile, FileMode.Create, FileAccess.Write, FileShare.None)) + using (GZipStream str = new GZipStream(outFile, CompressionMode.Compress)) + foreach (string sFilePath in sFiles) + { + string sRelativePath = sFilePath.Substring(iDirLen); + if (progress != null) + progress(sRelativePath); + CompressFile(sInDir, sRelativePath, str); + } + } + + public static void DecompressToDirectory(string sCompressedFile, string sDir, ProgressDelegate progress) + { + using (FileStream inFile = new FileStream(sCompressedFile, FileMode.Open, FileAccess.Read, FileShare.None)) + using (GZipStream zipStream = new GZipStream(inFile, CompressionMode.Decompress, true)) + while (DecompressFile(sDir, zipStream, progress)) ; + } + } +} diff --git a/Subsurface/Screens/LobbyScreen.cs b/Subsurface/Screens/LobbyScreen.cs index bb33a69b7..f2233466a 100644 --- a/Subsurface/Screens/LobbyScreen.cs +++ b/Subsurface/Screens/LobbyScreen.cs @@ -96,7 +96,7 @@ namespace Subsurface { base.Select(); - Map.Unload(); + //Map.Unload(); UpdateCharacterLists(); @@ -222,7 +222,8 @@ namespace Subsurface private bool StartShift(GUIButton button, object selection) { - Map.Load(Game1.GameSession.SaveFile); + + //Map.Load(Game1.GameSession.SaveFile); Game1.GameSession.StartShift(); diff --git a/Subsurface/Screens/MainMenu.cs b/Subsurface/Screens/MainMenu.cs index c3eddf30e..7e9ef24f1 100644 --- a/Subsurface/Screens/MainMenu.cs +++ b/Subsurface/Screens/MainMenu.cs @@ -55,23 +55,20 @@ namespace Subsurface new GUITextBlock(new Rectangle(0, 30, 0, 30), "Selected map:", Color.Transparent, Color.Black, Alignment.Left, menuTabs[(int)Tabs.NewGame]); mapList = new GUIListBox(new Rectangle(0, 60, 200, 400), Color.White, menuTabs[1]); - //string[] mapFilePaths = Map.GetMapFilePaths(); - //if (mapFilePaths!=null) - //{ - foreach (Map map in Map.SavedMaps) - { - GUITextBlock textBlock = new GUITextBlock( - new Rectangle(0, 0, 0, 25), - map.Name, - GUI.style, - Alignment.Left, - Alignment.Left, - mapList); - textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); - textBlock.UserData = map; - } - if (Map.SavedMaps.Count > 0) mapList.Select(Map.SavedMaps[0]); - //} + foreach (Map map in Map.SavedMaps) + { + GUITextBlock textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + map.Name, + GUI.style, + Alignment.Left, + Alignment.Left, + mapList); + textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); + textBlock.UserData = map; + } + if (Map.SavedMaps.Count > 0) mapList.Select(Map.SavedMaps[0]); + button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", GUI.style, Alignment.Right | Alignment.Bottom, menuTabs[(int)Tabs.NewGame]); button.OnClicked = StartGame; @@ -150,7 +147,7 @@ namespace Subsurface if (selectedMap == null) return false; - Game1.GameSession = new GameSession(selectedMap.FilePath, true, TimeSpan.Zero); + Game1.GameSession = new GameSession(selectedMap, TimeSpan.Zero); Game1.LobbyScreen.Select(); diff --git a/Subsurface/Screens/NetLobbyScreen.cs b/Subsurface/Screens/NetLobbyScreen.cs index 9a81b0b9b..4992832d9 100644 --- a/Subsurface/Screens/NetLobbyScreen.cs +++ b/Subsurface/Screens/NetLobbyScreen.cs @@ -6,6 +6,7 @@ using Subsurface.Networking; using FarseerPhysics; using FarseerPhysics.Factories; using FarseerPhysics.Dynamics; +using System.IO; namespace Subsurface { @@ -472,7 +473,7 @@ namespace Subsurface } else { - msg.Write(selectedMap.Name); + msg.Write(Path.GetFileName(selectedMap.FilePath)); msg.Write(selectedMap.MapHash.MD5Hash); } @@ -502,7 +503,7 @@ namespace Subsurface else { mapList.Select(map); - map.Load(); + //map.Load(); return true; } } diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 5cfeb61e0..ef430e917 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -133,6 +133,7 @@ + @@ -187,6 +188,9 @@ False .\FarseerPhysics MonoGame.dll + + C:\Users\Joonas\Desktop\SharpZipLib_0860_Bin\net-20\ICSharpCode.SharpZipLib.dll + False .\Lidgren.Network.dll @@ -218,16 +222,28 @@ PreserveNewest - + + PreserveNewest + + PreserveNewest PreserveNewest - + PreserveNewest - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + PreserveNewest @@ -271,6 +287,12 @@ PreserveNewest Designer + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/Subsurface/ToolBox.cs b/Subsurface/ToolBox.cs index 245368bd8..57b9bdd3d 100644 --- a/Subsurface/ToolBox.cs +++ b/Subsurface/ToolBox.cs @@ -128,50 +128,50 @@ namespace Subsurface } - public static void CompressStringToFile(string fileName, string value) - { - // A. - // Write string to temporary file. - string temp = Path.GetTempFileName(); - File.WriteAllText(temp, value); + //public static void CompressStringToFile(string fileName, string value) + //{ + // // A. + // // Write string to temporary file. + // string temp = Path.GetTempFileName(); + // File.WriteAllText(temp, value); - // B. - // Read file into byte array buffer. - byte[] b; - using (FileStream f = new FileStream(temp, FileMode.Open)) - { - b = new byte[f.Length]; - f.Read(b, 0, (int)f.Length); - } + // // B. + // // Read file into byte array buffer. + // byte[] b; + // using (FileStream f = new FileStream(temp, FileMode.Open)) + // { + // b = new byte[f.Length]; + // f.Read(b, 0, (int)f.Length); + // } - // C. - // Use GZipStream to write compressed bytes to target file. - using (FileStream f2 = new FileStream(fileName, FileMode.Create)) - using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false)) - { - gz.Write(b, 0, b.Length); - } - } + // // C. + // // Use GZipStream to write compressed bytes to target file. + // using (FileStream f2 = new FileStream(fileName, FileMode.Create)) + // using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false)) + // { + // gz.Write(b, 0, b.Length); + // } + //} - public static Stream DecompressFiletoStream(string fileName) - { - if (!File.Exists(fileName)) - { - DebugConsole.ThrowError("File ''"+fileName+" doesn't exist!"); - return null; - } + //public static Stream DecompressFiletoStream(string fileName) + //{ + // if (!File.Exists(fileName)) + // { + // DebugConsole.ThrowError("File ''"+fileName+" doesn't exist!"); + // return null; + // } - using (FileStream originalFileStream = new FileStream(fileName, FileMode.Open)) - { - MemoryStream decompressedFileStream = new MemoryStream(); + // using (FileStream originalFileStream = new FileStream(fileName, FileMode.Open)) + // { + // MemoryStream decompressedFileStream = new MemoryStream(); - using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress)) - { - decompressionStream.CopyTo(decompressedFileStream); - return decompressedFileStream; - } - } - } + // using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress)) + // { + // decompressionStream.CopyTo(decompressedFileStream); + // return decompressedFileStream; + // } + // } + //} public static XDocument TryLoadXml(string filePath) { diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 248f75092fca83a86ea45e4da828a8922ccf1fc6..605d748b44c69cb1494d1907b6696e8831f1c4ee 100644 GIT binary patch delta 15332 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 OvEv^D;n7ATSN<=K!bEQX