/// <summary>Loads and parses the map.ini from the current map path.</summary> private void LoadMapData() { if (m_filePath == "") return; if (!File.Exists(m_filePath + Program.MapIniFile)) { Debug.WriteLine("WARNING: map ini does not exist"); return; } try { //Why have the overhead of getprivateprofile when we can just do it ourself? m_lastLoad = m_filePath + Program.MapIniFile; FileStream stream = File.OpenRead(m_lastLoad); StreamReader reader = new StreamReader(stream); string line = ""; string subline = ""; string[] parts; string[] subparts; int zoneid; int mapid; int linenumber = 0; int idx = 0; FFXIZoneMaps zonemaps = null; FFXIImageMap map = null; while ((line = reader.ReadLine()) != null) { linenumber++; try { if (line.Length == 0 || line[0] == ';' || line[0] == '[') //only care about the data continue; //parse the key/value pair of the ini line parts = line.Split('='); if (parts.Length != 2) continue; //parse the zone/map pair subparts = parts[0].Split('_'); if (subparts.Length != 2) continue; zoneid = System.Convert.ToInt16(subparts[0], 16); if (!int.TryParse(subparts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out mapid)) continue; //parse the calc and range data subline = parts[1]; idx = subline.IndexOf(';'); if (idx > -1) subline = subline.Substring(0, idx); //kill comments following the data area subline = subline.Trim(); subparts = subline.Split(','); if (subparts.Length == 0 || ((subparts.Length - 4) % 6 != 0)) //ranges are specified in vector pairs continue; //get the zone object if (zonemaps == null || zonemaps.ZoneID != zoneid) { if (!m_zones.ContainsKey(zoneid)) { zonemaps = new FFXIZoneMaps(this, zoneid); m_zones.Add(zoneid, zonemaps); } else { zonemaps = m_zones[zoneid]; } } if (zonemaps.ContainsKey(mapid)) //only process the same zone/map combo once continue; //create the map object map = new FFXIImageMap(zonemaps, mapid, float.Parse(subparts[0], CultureInfo.InvariantCulture), float.Parse(subparts[1], CultureInfo.InvariantCulture), float.Parse(subparts[2], CultureInfo.InvariantCulture), float.Parse(subparts[3], CultureInfo.InvariantCulture) ); //add each range of values int i = 4; while (i < subparts.Length) { map.addRange( float.Parse(subparts[i], CultureInfo.InvariantCulture), //X1 float.Parse(subparts[i + 2], CultureInfo.InvariantCulture), //Y1 Y/Z swapped to standard vertex order. float.Parse(subparts[i + 1], CultureInfo.InvariantCulture), //Z1 Why must we perpetuate bad coordinate ordering? float.Parse(subparts[i + 3], CultureInfo.InvariantCulture), //X2 float.Parse(subparts[i + 5], CultureInfo.InvariantCulture), //Y2 Y/Z swapped here too. float.Parse(subparts[i + 4], CultureInfo.InvariantCulture) //Z2 ); i += 6; } zonemaps.Add(map); } catch (Exception ex) { Debug.WriteLine("error reading line " + linenumber + ": " + ex.Message); } } reader.Close(); } catch (Exception ex) { Debug.WriteLine("LoadMapData ERROR: " + ex.Message); } }
public FFXIImageMapRange(FFXIImageMap map, float x1, float y1, float z1, float x2, float y2, float z2) { //cache the mins/maxs m_map = map; SetRange(x1, y1, z1, x2, y2, z2); }
public override bool Poll() { if (Switching) return true; if (reader == null) return false; if (reader.HasExited) return false; if (!Valid) throw new InstanceException("FFXI could not be polled becuase the context is invalid.", InstanceExceptionType.InvalidContext); try { //grab the current zone id Int32 ZoneID = reader.ReadStruct<Int32>(pZoneID); if (ZoneID > 0xFF) ZoneID = ZoneID - 0x1BC; //stop all reading while the zone is in flux if (ZoneID == 0) { lastZone = -1; //make sure the data gets properly reset in case the player zones into the same zone (tractor, warp, etc) lastMapID = -1; return true; } //If the zone has changed, then clear out any old spawns and load the zone map if (ZoneID != lastZone || engine.Data.Empty) { //An edit to the map has been made. Inform the user they are about to lose thier changes // and give them a final opportunity to save them. if (engine.Data.Dirty) { //clone the map data MapData mapcopy = engine.Data.Clone(); //pass the closed data to another thread so the current zone can continue processing. DirtyZone(mapcopy); } zoneFinished = false; //get the zone name string shortName = ""; if (ZoneID < m_zoneNameShort.Count) shortName = m_zoneNameShort[ZoneID]; //grab the new zone name if (shortName == "") shortName = "Zone" + ZoneID.ToString(); //support unnamed zones, like the mog house //release zone resources consumed by the image map processor if (engine.ShowMapAlternative) { engine.MapAlternativeImage = null; m_imagemaps.ClearCache(lastZone); } //clear the old zone data and load in the new engine.Clear(); //clear both the spawn and map data engine.Data.ZoneName = shortName; engine.Data.LoadZone(shortName); //load the zone map lastZone = ZoneID; lastMapID = -1; } //read the pointer array in one big lump, and create spawns for any new id's detected Int32[] spawnList = reader.ReadStructArray<Int32>(pSpawnStart, listMax); //cant use intptr since its machine dependant for (uint i = 0; i < listMax; i++) { if (spawnList[i] > 0) { //only add new id's. each spawn is responsible for updating itself. if (!engine.Game.Spawns.ContainsIndex(i)) { //create the spawn and add it to the game data FFXISpawn spawn = new FFXISpawn(i, (IntPtr)spawnList[i], this); engine.Game.Spawns.Add(spawn); //spawn.DEBUGHOVER = "pointer: " + spawnList[i].ToString("X") + " index: " + i; //add the spawn to the server lookup table. this is used later to convert the claim id if (spawn.Type == SpawnType.Player) { if (m_ServerIDLookup.ContainsKey(spawn.ServerID)) m_ServerIDLookup[spawn.ServerID] = spawn; else m_ServerIDLookup.Add(spawn.ServerID, spawn); //add the server id to the lookup table } } } } //fill in the player and target UInt32 myID = reader.ReadStruct<UInt32>(pMyID); engine.Game.setPlayer(myID, true); UInt32 myTarget = reader.ReadStruct<UInt32>(pMyTarget); engine.Game.setTarget(myTarget, true); //force each spawn to self update engine.Game.Update(); //determine if the map image alternative requires processing if (engine.ShowMapAlternative && (lastPlayerLocation == null || (engine.Game.Player != null && !engine.Game.Player.Location.isEqual(lastPlayerLocation)))) { //Since the player has moved, determine if the map id has changed lastPlayerLocation = engine.Game.Player.Location.Clone(); curMap = m_imagemaps.GetCurrentMap(ZoneID, lastPlayerLocation); //only process if there is a map to display if (curMap != null) { /// IHM EDIT //Send the location in image coordinates to the engine. (I don't like doing it this way.) engine.LocInImage = curMap.Translate(engine.Game.Player.Location); //only process if the map has actually changed if (curMap.MapID != lastMapID) { engine.MapAlternativeImage = curMap.GetImage(); //set the background image RectangleF bounds = curMap.Bounds; //retrieve the map coodinate boundaries engine.MapAlternativeBounds = bounds; //set the origin/scale of the background image engine.Data.CheckBounds(bounds); //expand the map bounds (if necessary) to allow the map to be zoomed all the way out lastMapID = curMap.MapID; //set the map id so that the map isnt processed again until a change is made if (MapChanged != null) MapChanged(curMap, new EventArgs()); } } else if (engine.MapAlternativeImage != null) { //inform the engine that there is no map to display for the current location engine.MapAlternativeImage = null; lastMapID = -1; } } if (engine.Game.Spawns.Count > 0 && !zoneFinished) { zoneFinished = true; //automatically snap the range into view (if enabled) if (engine.AutoRangeSnap) engine.SnapToRange(); if (ZoneChanged != null) ZoneChanged(curMap, new EventArgs()); } return true; #if DEBUG } catch(Exception ex) { Debug.WriteLine("Error while polling the process: " + ex.Message); #else } catch { #endif return false; } }
/// <summary>Determines if the given map is bound to the zone.</summary> public bool ContainsValue(FFXIImageMap map) { return m_maps.ContainsValue(map); }
/// <summary>Creates a new map with the given id, scale, and offset</summary> public FFXIImageMap Create(int ID, float scale, float x, float y) { if (m_maps.ContainsKey(ID)) return m_maps[ID]; FFXIImageMap map = new FFXIImageMap(this, ID, scale, x, -scale, y); Add(map); return map; }
public FFXIMapImageEditor() { m_hovered = null; mapList = new LinkedList<FFXIImageMap>(); }
/// <summary>Adds the image map to the zone.</summary> public void Add(FFXIImageMap map) { m_maps.Add(map.MapID, map); }
private void DrawMap(FFXIImageMap map, Graphics g) { if (map == null) return; RectangleF bounds = map.Bounds; Image image = map.GetImage(); RectangleF dest = RectangleF.FromLTRB( window.Engine.CalcClientCoordX(bounds.Left), window.Engine.CalcClientCoordY(bounds.Top), window.Engine.CalcClientCoordX(bounds.Right), window.Engine.CalcClientCoordY(bounds.Bottom) ); if (image != null) { g.DrawImage(image, Rectangle.Round(dest), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel); } else { g.FillRectangle(bTitleBG, dest); g.DrawLine(pHandleBorder, dest.Left, dest.Top, dest.Right, dest.Bottom); g.DrawLine(pHandleBorder, dest.Left, dest.Bottom, dest.Right, dest.Top); } string mapinfo = "Map " + map.MapID + " Scale: " + map.XScale + " Offset: " + map.XOffset + "," + map.YOffset; SizeF size = g.MeasureString(mapinfo, SystemFonts.DefaultFont); float x = engine.CalcClientCoordX(bounds.X); float y = engine.CalcClientCoordY(bounds.Y); g.FillRectangle(bTitleBG, x, y, size.Width + 2, size.Height + 2); g.DrawString(mapinfo, SystemFonts.DefaultFont, bTitle, x + 1, y + 1); }
public void OnMouseLeave(EventArgs e) { m_hovered = null; }
public void OnMouseMove(MouseEventArgs e) { if (panMode) { if (editmode == 0 && edittarget == 1) { m_selectedMap.SetMapLocation( panViewOrigin.X + (float)(((panMouseOrigin.X - e.X) * m_selectedMap.XScale) / engine.Scale), panViewOrigin.Y + (float)(((panMouseOrigin.Y - e.Y) * -m_selectedMap.YScale) / engine.Scale) ); engine.UpdateMap(); } else { //default pan mode behavior window.Engine.ViewLocation = new PointF( (float)(panViewOrigin.X - (float)(panMouseOrigin.X - e.X)), (float)(panViewOrigin.Y - (float)(panMouseOrigin.Y - e.Y)) ); } } else { if (editmode == 0) { m_hovered = GetMapFromPoint(e.Location); if (m_hovered == null || (UserControl.ModifierKeys & Keys.Control) > 0) { window.Cursor = Cursors.Default; } else { window.Cursor = Cursors.SizeAll; } } } }
public void OnMouseDown(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { //if panning the map, then capture the current mouse location as the origin and enable the panning mode panViewOrigin = window.Engine.ViewLocation; panMouseOrigin = e.Location; panMode = true; if (editmode == 0) { m_selectedMap = GetMapFromPoint(e.Location); if (m_selectedMap == null || (UserControl.ModifierKeys & Keys.Control) > 0) { edittarget = 0; } else { if (m_selectedMap != mapList.First.Value) { mapList.Remove(m_selectedMap); mapList.AddFirst(m_selectedMap); ui.updateTopMostMap(); } panViewOrigin = new PointF(m_selectedMap.XOffset, m_selectedMap.YOffset); edittarget = 1; } } } }
public void RemoveMap(FFXIImageMap map) { if (imap.CurrentZone.ContainsValue(map)) { imap.CurrentZone.Remove(map.MapID); mapList.Remove(map); ui.updateMapInfo(); } }