Jump to content

Doctor

Members
  • Posts

    68
  • Joined

  • Last visited

  • Donations

    0.00 USD 

Everything posted by Doctor

  1. Server's in a wonky state. It's up, but group buffs aren't loading. Mining/freewarp appears to be infinite (or far beyond normal energy limits) Mining causes the reactor bar to fully drain, then instantly pop back once the item is extracted. Cloaking appears to be infinite (or very long) Sector backgrounds are not (always) loading Some people are reporting the group frame (where group members are shown) is also gone. It's apparently been like this for 3-4 hours at least.
  2. Right, I should explain. So, because of how many slots of ore exist per level, I have 5 vault characters for raw ore, and 2 for refined (not all refined is useful, so you need less). Then I have 5 more 'staging characters'. Those are the 5 TTs that fly with my JE so I can use them as mules while mining. So, the flow of ore/hulk stuff is like this: Roid -> JE -> Staging Character (until full stack) -> Vault character (until reserve quantity met) -> Refining character -> (2 possibles; selling character or refining vault). I don't really like the idea of having 'staging characters', but I'm not about to level up 5 more TTs from lvl 0, so...meh. Oh! And for the Hulk stuff, prototype gear specifically, I have a way to only save the (customizable) 120%+ quality stuff. In my case, weapons have to be at least 120% quality to get saved, and shields/reactors/engines can be 100% or better. But those are variables in the script and easy to change/customize.
  3. I'm still working on the ore move script (like everything, the devil is in the details...and there's a LOT of details). But here's an example of why I'm writing it... For char Dolladolla slot1 - Moving 300 Abyssian Dust in slot 0 to Doctorts For char Dolladolla slot2 - Moving 300 Celestial Ore in slot 7 to Doctorts For char Dolladolla slot3 - Moving 300 Conorite in slot 10 to Doctorts For char Dolladolla slot4 - Moving 300 Cupidite in slot 12 to Doctorts For char Dolladolla slot5 - Moving 300 Duplium Ore in slot 16 to Doctorts For char Dolladolla slot6 - Moving 300 Emperion in slot 19 to Doctorts For char Dolladolla slot7 - Moving 300 Helvatha in slot 21 to Doctorts For char Dolladolla slot8 - Moving 300 Idunium Ore in slot 25 to Doctorts For char Dolladolla slot9 - Moving 300 Inderite in slot 27 to Doctorts For char Dolladolla slot10 - Moving 300 Khnumium Ore in slot 32 to Doctorts For char Dolladolla slot11 - Moving 300 Leonite in slot 34 to Doctorts For char Dolladolla slot12 - Moving 300 Leonite in slot 36 to Doctorts Actual sending disabled. For char Dolladolla slot1 - Moving 300 Neutronium Ore in slot 41 to Doctorts For char Dolladolla slot2 - Moving 300 Pyrrhotite Gneiss in slot 46 to Doctorts For char Dolladolla slot3 - Moving 300 Raw Charybdis Voidstone in slot 50 to Doctorts For char Dolladolla slot4 - Moving 300 Raw Diamond in slot 52 to Doctorts For char Dolladolla slot5 - Moving 300 Raw Firerock in slot 56 to Doctorts For char Dolladolla slot6 - Moving 300 Raw Firerock in slot 57 to Doctorts For char Dolladolla slot7 - Moving 300 Raw Galactic Rimstone in slot 60 to Doctorts For char Dolladolla slot8 - Moving 300 Raw Hadecite in slot 61 to Doctorts For char Dolladolla slot9 - Moving 300 Raw Meteoric Diamond in slot 63 to Doctorts For char Dolladolla slot10 - Moving 300 Raw Meteoric Diamond in slot 64 to Doctorts For char Dolladolla slot11 - Moving 300 Raw Mica in slot 66 to Doctorts For char Dolladolla slot12 - Moving 300 Raw Scyllan Diamond in slot 68 to Doctorts Actual sending disabled. For char Rejecca slot1 - Moving 300 Andromesite in slot 2 to Doctorts For char Rejecca slot2 - Moving 300 Charon's Dust in slot 8 to Doctorts For char Rejecca slot3 - Moving 300 Gold Ore in slot 15 to Doctorts For char Rejecca slot4 - Moving 300 Hades Blood in slot 17 to Doctorts For char Rejecca slot5 - Moving 300 Hades Blood in slot 18 to Doctorts For char Rejecca slot6 - Moving 300 Hafnium Ore in slot 20 to Doctorts For char Rejecca slot7 - Moving 300 Halon in slot 22 to Doctorts For char Rejecca slot8 - Moving 300 Krypton in slot 26 to Doctorts For char Rejecca slot9 - Moving 300 Radium Ore in slot 37 to Doctorts For char Rejecca slot10 - Moving 300 Radon in slot 39 to Doctorts For char Rejecca slot11 - Moving 300 Raw Anthenicite in slot 41 to Doctorts For char Rejecca slot12 - Moving 300 Raw Charon Crystal in slot 45 to Doctorts Actual sending disabled. For char Shogunfive slot1 - Moving 300 Anubium Ore in slot 1 to Doctorts For char Shogunfive slot2 - Moving 300 Argon in slot 3 to Doctorts For char Shogunfive slot3 - Moving 300 Argon in slot 4 to Doctorts For char Shogunfive slot4 - Moving 300 Cobalite in slot 14 to Doctorts For char Shogunfive slot5 - Moving 300 Fluorine in slot 16 to Doctorts For char Shogunfive slot6 - Moving 300 Fluorine in slot 17 to Doctorts For char Shogunfive slot7 - Moving 300 Fluorine in slot 18 to Doctorts For char Shogunfive slot8 - Moving 300 Neon in slot 30 to Doctorts For char Shogunfive slot9 - Moving 300 Neon in slot 31 to Doctorts For char Shogunfive slot10 - Moving 300 Raw Alexandrite in slot 36 to Doctorts For char Shogunfive slot11 - Moving 300 Raw Lapis Lazuli in slot 46 to Doctorts For char Shogunfive slot12 - Moving 300 Raw Malachite in slot 48 to Doctorts Actual sending disabled. For char Dolladolla slot1 - Moving 300 Raw Tincal in slot 69 to Doctorts For char Dolladolla slot2 - Moving 300 Raw Voidgem in slot 71 to Doctorts For char Dolladolla slot3 - Moving 300 Stojsavline in slot 74 to Doctorts For char Dolladolla slot4 - Moving 300 Stygian Blacksand in slot 76 to Doctorts For char Dolladolla slot5 - Moving 300 Stygian Blacksand in slot 77 to Doctorts For char Dolladolla slot6 - Moving 300 Vaneon in slot 83 to Doctorts For char Dolladolla slot7 - Moving 300 Vaneon in slot 84 to Doctorts For char Dolladolla slot8 - Moving 300 Wexeon in slot 88 to Doctorts For char Dolladolla slot9 - Moving 300 Yunieon Gas in slot 91 to Doctorts Actual sending disabled. For char Dolladolla slot1 - Moving 300 Ambrosia Crude in slot 95 to Eightnineore For char Dolladolla slot2 - Moving 300 Boragon in slot 93 to Eightnineore For char Dolladolla slot3 - Moving 300 Emperion in slot 18 to Eightnineore For char Dolladolla slot4 - Moving 300 Minosium Ore in slot 38 to Eightnineore For char Dolladolla slot5 - Moving 300 Persephonite in slot 44 to Eightnineore For char Dolladolla slot6 - Moving 300 Vanirum Ore in slot 86 to Eightnineore Actual sending disabled. For char Dolladolla slot1 - Moving 300 Apollonite in slot 3 to Sixsevenore For char Dolladolla slot2 - Moving 300 Demeter's Tears in slot 14 to Sixsevenore For char Dolladolla slot3 - Moving 300 Horusium Ore in slot 24 to Sixsevenore For char Dolladolla slot4 - Moving 300 Iridium Ore in slot 29 to Sixsevenore For char Dolladolla slot5 - Moving 300 Iridium Ore in slot 30 to Sixsevenore For char Dolladolla slot6 - Moving 300 Raw Eye Stone in slot 54 to Sixsevenore For char Dolladolla slot7 - Moving 300 Tantalum Ore in slot 79 to Sixsevenore Actual sending disabled. For char Greedincarnate slot1 - Moving 300 Diridium Crystal in slot 9 to Doctorts For char Greedincarnate slot2 - Moving 300 Diridium Crystal in slot 10 to Doctorts For char Greedincarnate slot3 - Moving 300 Raw Amethyst in slot 31 to Doctorts Actual sending disabled. For char Greedincarnate slot1 - Moving 300 Raw Topaz in slot 41 to Lvloneore For char Greedincarnate slot2 - Moving 300 Raw Topaz in slot 42 to Lvloneore Actual sending disabled. For char Rejecca slot1 - Moving 300 Adamantine Ore in slot 0 to Sixsevenore For char Rejecca slot2 - Moving 300 Discordite in slot 13 to Sixsevenore For char Rejecca slot3 - Moving 300 Osirium Ore in slot 31 to Sixsevenore For char Rejecca slot4 - Moving 300 Raw Flawless Ruby in slot 49 to Sixsevenore For char Rejecca slot5 - Moving 300 Raw Flawless Ruby in slot 50 to Sixsevenore For char Rejecca slot6 - Moving 300 Stygian Blackwater in slot 66 to Sixsevenore For char Rejecca slot7 - Moving 300 Stygian Blackwater in slot 67 to Sixsevenore For char Rejecca slot8 - Moving 300 Stygian Blackwater in slot 68 to Sixsevenore For char Rejecca slot9 - Moving 300 Stygian Blackwater in slot 69 to Sixsevenore Actual sending disabled. For char Rejecca slot1 - Moving 300 Raw Heartstone in slot 52 to Doctorts For char Rejecca slot2 - Moving 300 Raw Icy Pearl in slot 54 to Doctorts For char Rejecca slot3 - Moving 300 Xenon in slot 77 to Doctorts For char Rejecca slot4 - Moving 300 Xenon in slot 78 to Doctorts For char Rejecca slot5 - Moving 300 Zalmoxium Ore in slot 80 to Doctorts Actual sending disabled. For char Rejecca slot1 - Moving 300 Brood Oil in slot 6 to Fourfiveore For char Rejecca slot2 - Moving 300 Hawkinsite in slot 24 to Fourfiveore For char Rejecca slot3 - Moving 300 Raw Skystone in slot 57 to Fourfiveore For char Rejecca slot4 - Moving 300 Rhodite in slot 63 to Fourfiveore For char Rejecca slot5 - Moving 300 Titanium Ore in slot 73 to Fourfiveore Actual sending disabled. For char Shogunfive slot1 - Moving 300 Vanadium Ore in slot 64 to Doctorts Actual sending disabled. For char Shogunfive slot1 - Moving 300 Meteoric Sand in slot 28 to Fourfiveore For char Shogunfive slot2 - Moving 300 Solar Sweet Oil in slot 53 to Fourfiveore Actual sending disabled. For char Shogunfive slot1 - Moving 300 Raw Citrine in slot 41 to Twothreeore For char Shogunfive slot2 - Moving 300 Star Iron Ore in slot 55 to Twothreeore Actual sending disabled. The script runs in multiple phases. Moving partial stacks to the staging characters, Moving full stacks or raw ore on the staging characters to the vault chars, then any excess to the designated 'Refining' character (doctorTS in this case) This is what is shown above. If you look for Emperion you can see this balancing behavior in action. I want to keep 300 in reserve on my vault, and any extra gets refined and either sold or saved (see step 3). Despite the doctorTS line printing first, it actually did slate a stack for the vault character (Eightnineore) first, but so few stacks went to the vault vs needing to go to doctorTS that the doctorTS batch ended up 'sending' (this is in debug mode, so it didn't actually move it) first. Moving refined items to their vault(s) or the designated Sell Character (someone with Negotiate 7 :D) In reality, it would never be able to do all 3 in one pass. You'd have to log in between phases 2 and 3 and actually refine the ore. Also, the only way to collapse stacks is in-game, so that remains a manual step. But still...if you sit and count, that's 66 stacks of ore for DoctorTS to refine. And to know that I needed to move those 66 stacks I would have to check *at least* 5 different inventories. This tool is SO much less mental work. yay. Oh, and the fact that it's breaking up into little transfers of 5, 1, 2, etc, that's because it's honoring the portal rules and treating each source:destination pair as unique. So it will do batches of 12 when it can, and when it can't, it will do as many as it can. I haven't actually tested whether the API supports more than 12 items, having one send from a single source go to multiple dests, and various other things like that...I don't plan to. Or if I do it will be purely to sate my curiosity. I imagine the handler is robust against such non-typical uses. But I also admit to raw curiosity. And, yes, it works with hulk contents too. In my use case, Bogeril stuff goes to one character, and then I have separate vaults for Prototype Weapons/shields/reactors/engines. I also have regional vaults for various turn-ins (so Terran space suits go to Earth, Progen ones go to Mars, as do all the Gene Maps, etc). Because of how it's designed, it would not be particularly difficult to change it to be able to move ore in bulk. So if you have a TT making 100s of stacks of ammo for alts, this could also automate moving that, with minor effort. And yes, Stygian Blackwater is INCREDIBLY abundant. P.S. Yes, I say 'automate'. It's semi-auto. You have to manually trigger it, and do other manual stuff around it. It's automatic like a semi-auto handgun is automatic. You still have to do manual stuff to make it go bang.
  4. For such things, I've honestly found chatGPT to be a huge time saver. I'd never touched javascript before (but I had programmed in other languages) and it was able to teach me enough javascript to make something work. It's also saved me a lot of time writing autohotkey functions because it can type *way* faster than I can, and I can generally tell it "do X" and know X is possible. But like, it can teach a lot of things as well as your average school teacher (meaning it also, like the human, gets stuff wrong). It has infinite patience (in my experience anyway) so it's actually pretty decent at helping troubleshoot stuff. It is FAR from perfect though. As for meta tasks, idk, maybe pick your favorite sector and make sure every drop in the wiki is up to date. Maybe bring all 6 damage types and find out which resists are *actually* the weakest for each mob. ...I'm not very creative. I'm sure you'll figure something out.
  5. I can't speak to solo raiding. I know some raids specifically (Controller?) got changed to make solo-raiding impossible. Others will have to chime in on that. Keybind copy: Not sure. The keybinds are stored in a flatfile in the install directory, but each file is set per-character, and...yeah, idk. To target asteroids I just hit 'x' (target nearest object) and d/c (next closest/farthest) to cycle through targets. Autohotkey is best for juggling multiple clients. I have a simple F2 loop {meaning push F2 to activate} (look in the main AHK thread for my functions) that will cycle through all windows, target the group leader's target, and fire all guns. I also added in a way to activate specific skills on specific characters. Though, some are kinda wonky (shield sap will NEVER activate if G-link is pressed within 1 second of it, for...some bloody reason). Also, before you try to use ControlSend, Westwood appears to have completely disabled input to the game client (outside of bringing the window into focus) when the window is out of focus, so sending instructions to a window that is NOT the active one appears to be impossible. If you figure out a way how to, do tell! And yeah, I have 1080p monitors, but when multiboxing I play with 3 720p windows per screen (2 up top, one centered in the bottom). I can't see the entire window, but I can see the shield bars and current target of every char. Look at the "FPS Cap" thread for how to use Reshade to enable Vsync and thus make your multiboxing easier (without that the game tries to render at around 1000 FPS)
  6. The end-game loop that Westwood envisioned was: Acquire raid gear Take hull damage acquiring other raid gear (combat was balanced around hull taking, and hull tanking eventually results in quality loss) Re-run old raids to acquire degraded gear For others of us, we build tools. Codemonkey and Winlander have been working on formatting/adding content to the wiki (as well as MANY others who added content in the 5+ years since its founding). I am working on a mapping tool that will show where all the ore fields, grav wells, mob spawns, etc are. I wrote an autohotkey script that simplified FN-NV trade runs down to pressing a single button over and over (plus walking around in stations manually). I wrote an AHK script that would let you easily move ores to alts without having to manually inspect them (good when mining fields with large level spreads that require mules). I made a tampermonkey script that changes the Account Vault to be click-to-select instead of drag-and-drop (it also adds filters). So...stuff like that can keep you busy. So...either you make your own meta content, you do the WW gameplay loop, or you say "ok, I won" and play another game.
  7. Unfortunately that's not true. Grail Water seems to be one of the rarest minerals in the game. I still haven't managed to mine out the 300 boronite for the chavez faction mission. No joke, I might actually hit 300 aesirium before I get 300 boronite. The main thing I'm looking forward to is finally having a list of "Ok, you want to find this ore? Here are the places to look." and have that be based on something approaching sane data. At least then I'll know I'm not crazy for thinking some minerals are super rare. To give you some sense, I have around 1/2 the sectors in the game mapped right now, and the size of the DB DOUBLED just from all the roid data. And my roid data storage is very efficient; only ints. So...yeesh. I will be rich beyond the dreams of avarice though. All of my TTs have at least 25m to their names just from selling stacks of refined lvl 8 ores. And that's *just* the extra stacks. I keep 1 (or more) stacks in reserve not just of lvl 8, but everything. The exceptions are the 'literally useless' ores like Firerock, Icy Pearl, Vaneon, etc. Things that have no uses either raw or refined. But yeah, my lvl 8 mule is full of ore, so it's time to sit down and write that script I had mentioned as making more sense instead of caching character IDs on the account vault page. By the time I sell off all the extra stacks I've gotten from just this most recent pass, I'd be shocked if I wasn't at 50m or better on all my TTs. at least I won't have to worry about money for a while. 😛 Fun note: the easiest way to move cash from one char to another is actually stacks of refined lvl 8 ore. Each stack is worth ~2m after negotiate is factored in. As for its utility to normal people, depends. I got the idea to mine with TT alts from another JE (before my JE was 150) and he had those TTs partially to sig-tank, and partially to hold ore. Back then I assumed the TS was going to be the best miner. Thankfully, he enlightened me to the utility of using the Martyr's Heart and a JE. The TS is a powerhouse, but it's kneecapped by it's lvl 8 reactor. Unless you intend to mine with a JS giving you every recharge and shunt buff there is...it just can't keep up with what a JE can do solo. Anyway, I do believe this will be useful to others. They probably won't need all 5 characters, but it is not hard to limit the source to only use 1/2/3/etc alts. I think the main problem is most people don't read the forums. In game, people are shocked to know there's a new mapping tool. Also, at a higher level, I think the code itself has merit. If one wants to learn autohotkey, what I'm doing is pretty clean, clear, and makes sense. GDIP is a PITA to use, but once you figure out what to do it's super powerful. autohotkey + GDIP helped me solve a $25 million problem IRL a few years ago. So...yeah. Part of sharing is also showing problem solving, solution options, and whatever else. I don't know why you feel the need to continually pretend my contributions have little to no value, but it is unappreciated and wrong.
  8. Yes, I know there's an autohotkey (AHK) thread already. Maybe I'm just an attention whore. I want to share what I've got because I find it super useful (at least to me). As some may know, I'm working on a mapping tool that will (eventually) let you see where all the mobs and roids in the game are. Right now I'm working on roids. To make this less masochistic, I fly with 5 TTs. 4 of the TTs get a 2-level band of ore because *usually* that fits into a single TT hold (Lagarto is an exception, there are probably others). So one char gets lvl 1-2 ores, 3-4, 5-6, 7-8, and the last one gets hulk contents, pop rock mob contents, and lvl 9 ores. Except for Lagarto, this works out where I can mine out an entire sector without needing to dock and dump. It was getting tedious having to sort the ore to my alts. So, I sat down and made autohotkey do it for me. Now, this requires GDIP, which is ULTRA finicky. Like, upgrading AHK minor versions can completely break it. But, when it works, it's glorious. For the maximum chance at success: I am using the Unicode 64-bit version of AHK 1.1.37.01. I have attached a .zip containing both the images (needles) and libraries (Gdip_all/Imagesearch) needed. (code at bottom of this post for length reasons) I plan to update this thread with additional goodies as I create them. Assumptions: Your windows are titled by your accounts. So, for example, the window where DoctorJE lives is always titled 'enb-61'. Because it's on my 6th game account. Whereas my PW/my ore TT for lvl 1-2 ore live on enb-51. Check outif you want to see the code for how I do this. You are playing at 1280x720 It will work with other resolutions, you just need to update the pixel coordinates at the top of the file. Note: for things like INVENTORY_SCREEN_PIXELS, [61,320] are the coordinates of the first inventory slot (top-left) and 77 is the X offset (so slot 5 is 77px right of slot 1) and 55 is the Y offset (slot 2 is 55px below slot 1). I use this convention in many places. "Why not use ImageSearch instead of Gdip?!" ImageSearch is MUCH slower. I can get the ilvl of every ore in the hold in less than a second with Gdip. I need around 15 seconds to do the same with ImageSearch. I'm sure to a normal person that isn't a problem, but to me, it's nails on a chalkboard. GDIP is also needed if I ever end up OCRing stuff. I tried to use Tesseract OCR to get the itemlvl for me, but it turned out to be way too much of a PITA, and not reliable. The reason why is that GDIP makes it easy to take a screenshot of the whole screen, then crop it. Normal AHK can't really do that. "What's the deal with isOre()?" So, the game client doesn't consistently render the icons for things in your hold. Take hydrocarbon results (the blue and white cylinder). If you have a lvl 5 and a lvl 8 in your hold, and you look at them in photoshop/gimp, you'll see that they are not identical and mis-aligned by 1/2 a pixel. That isn't something I can correct for in Gdip/AHK. To really classify those properly, I'd need to use a tool like OpenCV, or train a model using fast.ai as an image classifier. That's a level of headache I'm just not interested in right now. But I'll probably do it. Maybe. The only purpose of the isOre() function was to find hulk /mob contents and move those to one character (since, without that, Debris goes to my lvl 1-2 char, instead of to the one I want to hold hulk-stuff). Hulks are rare enough I just handle this special case by hand atm. On a higher level, I suspect that once I start using openCV, I'll use it for a lot of things (if it has any sort of performance at all) because being able to visually classify things sounds HUGELY more time saving than what I have to do right now. Or possibly training some sort of neural network. I've never seen either of those perform particularly fast, but...meh. I think you can see why I didn't keep going down this rabbit hole. The code: ;Scaled for 1280 window ;startx, starty, xoffset, yoffset INVENTORY_SCREEN_PIXELS:=[61,320,77,55] TRADE_SCREEN_PIXELS:=[493,291,95,75] TRADE_BUTTON:=[1135,500] CONFIRM_BUTTON:=[699,433] VAULT_SCREEN_PIXELS:=[440,268,75,54] FORMATION_BUTTON:=[1178, 269] FORMATION_MENU_OPTION:=[1181, 228] FORMATION_PIXEL_CHECK:=[1175,266] ASSIST_LEADER_BUTTON:=[1225, 444] ROID_LEVEL_LOCATION:=[1165,650,1180,690] #Include gdip_imageSearch\Gdip_All.ahk #Include gdip_imageSearch\Gdip_ImageSearch.ahk If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } OnExit, EXIT_LABEL ;CTRL + SHIFT + y - For Ore mining: Move ores to alts. ^+y:: KeyWait CTRL KeyWait Shift ORE_SLOTS := 30 ;Which inv slot is in the top-right? first_slot_visible := 1 12_window := "enb-51" 12_moves :=[] 12_idx_and_len :=[1,0] 34_window := "enb-41" 34_moves := [] 34_idx_and_len :=[1,0] 56_window := "enb-91" 56_moves := [] 56_idx_and_len :=[1,0] 78_window := "enb-81" 78_moves := [] 78_idx_and_len :=[1,0] 9_window := "enb-21" 9_moves := [] 9_idx_and_len :=[1,0] item_level_needles := [] IfWinActive enb-61 { ;Step 1, build a cache of the needles we need. Loop, 9 { needle_name:="C:\YOUR_PATH_TO\item_level_" A_Index ".png" file_needle:=Gdip_CreateBitmapFromFile(needle_name) item_level_needles[A_Index] := file_needle } ;Step 2, get a screenshot of the window. screenshot_haystack:=getGameScreen_gdip() ;Step 3, classify inventory slots Loop, %ORE_SLOTS% { slot:=A_Index ;Advance to next set of pages. if( slot > 11 && Mod(slot-1, 12) == 0) { ;Scaled for 1280 window Mousemove, 116,256 send {WheelDown 3} Sleep 50 ;Update Screenshot on change Gdip_DisposeImage(screenshot_haystack) screenshot_haystack:=getGameScreen_gdip() } ;Non-ore items (Hulk/mob drops) go to the char that gets lvl 9 ores. ;This method doesn't work, see function for details. /* isOre:=getIsOre(slot, ORE_SLOTS) if(isOre == 0) { 9_moves.Push(slot) continue } */ ilvl:=getInvItemLevel(screenshot_haystack, slot, ORE_SLOTS, item_level_needles) if(ilvl == -1) { ;This happens on an empty slot continue } else if(ilvl == 1 || ilvl == 2) { 12_moves.Push(slot) 12_idx_and_len[2] := 12_idx_and_len[2] + 1 } else if(ilvl == 3 || ilvl == 4) { 34_moves.Push(slot) 34_idx_and_len[2] := 34_idx_and_len[2] + 1 } else if(ilvl == 5 || ilvl == 6) { 56_moves.Push(slot) 56_idx_and_len[2] := 56_idx_and_len[2] + 1 } else if(ilvl == 7 || ilvl == 8) { 78_moves.Push(slot) 78_idx_and_len[2] := 78_idx_and_len[2] + 1 } else if(ilvl == 9) { 9_moves.Push(slot) 9_idx_and_len[2] := 9_idx_and_len[2] + 1 } else { Msgbox, Unknown item in %slot%, got %ilvl% } } ;Rewind window to starting position. Mousemove, 116,256 send {WheelUp 10} Sleep, 50 ;Step 4, Start moving trade items initial_target:=true while(12_idx_and_len[1] <= 12_idx_and_len[2]) { 12_idx_and_len[1] := makeTrades(12_window, 12_idx_and_len, 12_moves, first_slot_visible, ORE_SLOTS, initial_target) initial_target:=false } initial_target:=true while(34_idx_and_len[1] <= 34_idx_and_len[2]) { 34_idx_and_len[1] := makeTrades(34_window, 34_idx_and_len, 34_moves, first_slot_visible, ORE_SLOTS, initial_target) initial_target:=false } initial_target:=true while(56_idx_and_len[1] <= 56_idx_and_len[2]) { 56_idx_and_len[1] := makeTrades(56_window, 56_idx_and_len, 56_moves, first_slot_visible, ORE_SLOTS, initial_target) initial_target:=false } initial_target:=true while(78_idx_and_len[1] <= 78_idx_and_len[2]) { 78_idx_and_len[1] := makeTrades(78_window, 78_idx_and_len, 78_moves, first_slot_visible, ORE_SLOTS, initial_target) initial_target:=false } initial_target:=true while(9_idx_and_len[1] <= 9_idx_and_len[2]) { 9_idx_and_len[1] := makeTrades(9_window, 9_idx_and_len, 9_moves, first_slot_visible, ORE_SLOTS, initial_target) initial_target:=false } for index in item_level_needles Gdip_DisposeImage(item_level_needles[index]) Gdip_DisposeImage(screenshot_haystack) SoundBeep } return cropImage(pBitmapOld, tl_x, tl_y, br_x, br_y, byref cropped, save_to="", should_save=false) { NewWidth := br_x - tl_x NewHeight := br_y - tl_y xOffset:= tl_x yOffset := tl_y ;BMP Format := 0x26200A ;PNG ;Format := 0x3147504E cropped := Gdip_CreateBitmap(NewWidth, NewHeight, Format) G := Gdip_GraphicsFromImage(cropped) Gdip_SetSmoothingMode(G, 4) Gdip_SetInterpolationMode(G, 7) Gdip_DrawImage(G, pBitmapOld, 0,0, Gdip_GetImageWidth(pBitmapOld), Gdip_GetImageHeight(pBitmapOld),xOffset,yOffset,Gdip_GetImageWidth(pBitmapOld), Gdip_GetImageHeight(pBitmapOld)) if(should_save) { Gdip_SaveBitmapToFile(cropped,save_to) } } findImage(screenshot_haystack,file_needle,byref outx, byref outy, x1=0,y1=0,x2=0,y2=0,debug=false) { variation:=0 ;1 = top->left->right->bottom search_dir:=1 trans_color:=0xFFFFFF outx:=-1 outy:=-1 answer:=Gdip_ImageSearch(screenshot_haystack,file_needle, LIST,x1,y1,x2,y2,variation,trans_color,search_dir,1) Loop, Parse, LIST, `n { StringSplit, Coord, A_LoopField, `, Gdip_GetImageDimensions(file_needle,img_x,img_y) outx:=Coord1 + img_x/2 outy:=Coord2 + img_y/2 if(debug == true) { Msgbox, Hit %x% %y% o %x_offset% i %img_x% } ;msgbox %Coord1%, %Coord2%, 0 } if(debug == true) { MsgBox, % "Returned: " answer "`n`n" LIST "`n" outx ;msgbox, %x1%,%y1%,%x2%,%y2% ;Gdip_SaveBitmapToFile(screenshot_haystack, "area.png") ;saves image to file } } getGameScreen_gdip() { WinGet,hwnd,ID,A ;screenshot_haystack:=Gdip_BitmapFromHWND(hwnd) WinGetPos, wx, wy, ww, wh, ahk_id %hwnd% screen:=wx . "|" . wy . "|" . ww . "|" . wh screenshot_haystack := Gdip_BitmapFromScreen(screen) return screenshot_haystack ;Don't forget to Gdip_DisposeImage(screenshot_haystack) } getInvItemLevel(screenshot_haystack, slot_num, inv_slots, needle_images) { results := invSlotIDToPixels(slot_num, inv_slots) ;Search area for VIII (largest) is 20x8 px SEARCH_AREA_SIZE := [22,9] ;The -10 and -21 offsets here are not related to SEARCH_AREA_SIZE, they are the offset between where INVENTORY_SCREEN_PIXELS points and where the item lvl is. src_x:=results[1] - 10 src_y:=results[2] - 19 end_x:=src_x+SEARCH_AREA_SIZE[1] end_y:=src_y+SEARCH_AREA_SIZE[2] cropped_img:="" cropImage(screenshot_haystack, src_x,src_y,end_x,end_y, cropped_img) for index,value in [9,8,7,6,4,5,3,2,1] { findImage(cropped_img,needle_images[value],matchX, matchY, 0,0,0,0) if(matchX != -1 && matchY != -1) { Gdip_DisposeImage(cropped_img) return value } } Gdip_DisposeImage(cropped_img) return -1 } getScrollsNeeded(current_tl_slot, target_slot, max_slots) { if(current_column_index > max_column_index) { Msgbox, Programmer error: current_tl_slot is %current_tl_slot% which is larger than allowed. } if(target_slot <= current_tl_slot + 11 && target_slot >= current_tl_slot) { return 0 } current_column_index := FLOOR((current_tl_slot - 1) / 4) target_column_index := FLOOR((target_slot - 1) / 4) max_column_index := FLOOR((max_slots-1) / 4)-2 if(target_column_index > max_column_index) { return max_column_index - current_column_index } ;If we are on the last (partial) page: cols_to_normalize:= 0 if(current_tl_slot > max_column_index*4) { cols_to_normalize := -1 * MOD(max_column_index, 3) } current_page := FLOOR((current_tl_slot - 1) / 12) target_page := FLOOR((target_slot - 1) / 12) scrolls := 3 * (target_page - current_page) + cols_to_normalize return scrolls } invSlotIDToPixels(slot_num, max_slots) { global INVENTORY_SCREEN_PIXELS inv_row_id:=MOD(slot_num-1, 4) inv_col_id:=FLOOR((slot_num-1)/4) relative_col_id:=MOD(inv_col_id, 3) max_cols := CEIL(max_slots / 4) last_full_page_slot := FLOOR(max_slots/12)*12 if(slot_num > last_full_page_slot) { cols_to_add := 3-MOD(max_cols, 3) relative_col_id := relative_col_id + cols_to_add } src_x:=INVENTORY_SCREEN_PIXELS[1] + INVENTORY_SCREEN_PIXELS[3]*relative_col_id src_y:=INVENTORY_SCREEN_PIXELS[2] + INVENTORY_SCREEN_PIXELS[4]*inv_row_id return [src_x, src_y] } makeTrades(window_title, idx_and_len, movelist, byref first_slot_visible, max_slots, initial_targeting) { global ASSIST_LEADER_BUTTON, TRADE_BUTTON, CONFIRM_BUTTON moves_to_make := idx_and_len[2]+1 - idx_and_len[1] if(moves_to_make < 1) { return [idx_and_len[1], first_slot_visible] } if(moves_to_make > 6) { moves_to_make:=6 } if WinExist(window_title) { WinActivate, %window_title% } else { return [idx_and_len[1], first_slot_visible] } if(initial_targeting) { MouseClick, left, ASSIST_LEADER_BUTTON[1]-100, ASSIST_LEADER_BUTTON[2] Sleep, 1500 } MouseClick, left, TRADE_BUTTON[1], TRADE_BUTTON[2] Sleep, 250 WinActivate, enb-61 Sleep, 50 Loop, %moves_to_make% { inv_slot_id := movelist[idx_and_len[1]] inv_xy := invSlotIDToPixels(inv_slot_id, max_slots) trade_xy := tradeSlotIDToPixels(A_Index) scrolls_needed := getScrollsNeeded(first_slot_visible, inv_slot_id, max_slots) if( scrolls_needed != 0 ) { fixed_scrolls := ABS(scrolls_needed) Mousemove, 116,256 if( scrolls_needed > 0 ) { send {WheelDown %fixed_scrolls%} } else { send {WheelUp %fixed_scrolls%} } Sleep 50 ;debugval := first_slot_visible + (4 * scrolls_needed) ;Msgbox, Updating FSV from %first_slot_visible% to %debugval% with %scrolls_needed% called with %inv_slot_id% and %max_slots% first_slot_visible := first_slot_visible + (4 * scrolls_needed) } ;for debugging ;x1:=inv_xy[1] ;y1:=inv_xy[2] ;x2:=trade_xy[1] ;y2:=trade_xy[2] ;Msgbox, Moving inv slot %inv_slot_id% at %x1% %y1% to trade slot %A_Index% at %x2% %y2% idx_and_len[1] := idx_and_len[1] + 1 ;Move the mouse to the clickdrag start BEFORE you push shift! MouseMove, inv_xy[1], inv_xy[2] Send, {Shift down} MouseClickDrag, left, inv_xy[1], inv_xy[2], trade_xy[1], trade_xy[2] Send, {Shift up} Sleep, 50 } MouseClick, left, CONFIRM_BUTTON[1], CONFIRM_BUTTON[2] ;Important! Function must re-focus the character with ore to move. WinActivate, %window_title% Sleep, 50 ;Msgbox, Debug MouseClick, left, CONFIRM_BUTTON[1], CONFIRM_BUTTON[2] WinActivate, enb-61 ;Trade window hangs around after a trade finishes. Wait for it to go away. Sleep, 3000 return idx_and_len[1] } tradeSlotIDToPixels(slot_num) { global TRADE_SCREEN_PIXELS trade_row_id:=MOD(slot_num-1, 2) trade_col_id:=FLOOR((slot_num-1)/2) dest_x:=TRADE_SCREEN_PIXELS[1] + TRADE_SCREEN_PIXELS[3]*trade_col_id dest_y:=TRADE_SCREEN_PIXELS[2] + TRADE_SCREEN_PIXELS[4]*trade_row_id return [dest_x, dest_y] } EXIT_LABEL: ; be really sure the script will shutdown GDIP Gdip_Shutdown(pToken) EXITAPP ore_mover_ahk.7z @Codemonkeyx Credit where it's due. You were right, logging via data files was a better choice. This script was another thing that needed to happen. I just mined out the big PITA field in Rag for the second time...I beat the respawn easily now. Partly because I have 5 TTs instead of 2, and partly because I can cloak, push 3 buttons, wait about 1 minute, and have a completely clean hold, ready to keep mining. My god...if I could have started with this...
  9. @Woodstock HGM Since I know you care about R4c this is what the ore fields there look like. I still don't have mouse-over coordinates for navs coded in yet, but maybe someone will find this useful for knowing where to mine in R4c. Mostly lvl 6-7 gas, with some 5 and 8. The non-gas roids are pretty scarce but the rock field has some lvl 9 roids.
  10. Grissom Meteorological Site has an extra space at the end of the name in-game. 'Grissom Meteorological Site ' is the in-game name. I'm not sure how much breaks if that typo is fixed, but I wanted someone to be aware of it.
  11. Tarsis needs a redesign. "That doesn't look so bad" "Me brain like rock. Wat problem?" This is a low level zone. OL10s come here. And they leave by OL30. Realistically, the PS is the only character (other than me, and a few other strangers) that will ever mine here. That means characters with 20-22 cargo slots (via: https://www.net-7.org/wiki/index.php?title=Hull_Upgrades#Cargo_Capacity_Comparison) Every single TECH LEVEL of roid here takes up enough cargo slots to reasonably fill a PS's cargo hold, especially when accounting for ammo and the fact that the Red Dragon field guards are out in force, so the PS will need some slots for ammo. Ore fields drop 'sub-level' ores. Meaning a tech 3 roid may have tech 3 and/or tech 2 ores in it. So even if the fields were 1-level wide (only tech 3 roids) you'd still need 15 + 17 = 32 cargo slots to mine out that ONE FIELD. This is insanity. The actual fields, as they are now, are tech 1-3 at the southern end, and tech 3-5 at the northern end. Tech 3-5 is *actually* tech 2-5, so any given field in this sector will take 51 cargo slots to mine. This.is.insane. The fields are mixed, so you cannot focus on one roid type and still get a field clear bonus At OL 30, the station is so far away, and warp is so slow, that you cannot focus on mining out one type of roid, and make it through all 4 types, before the field respawns. Making field clear bonuses (which only exist to ensure explore XP from mining is in-line with other activities) impossible to earn. I'm a OL150 JE with 5 TTs to hold all my mining stuff and damn-near 8000 warp speed. This is infuriating for *me* to mine out. To a newbie PS, this is just soul-crushing. This is not how mining is almost everywhere else in the game. "How 2 fix?" I see these options Separate the fields and make them pure by roid type. Rock fields would need to be changed to be 1-3 and 4-5 though, due to the number of ores in rock-type roids. Other field types would not need level band adjustments. Leave the fields mixed, but disable sub-level spawning (so Tech 3 roids only drop tech 3 ores) and limit each field to a 1-level spread (so ONLY tech 3 roids in a field). And just because, here's a list of all the ores, in their quantities, that dropped before I gave up (this is roughly 90% of a complete mine-out, with minor repeats) Level Roid Source Ore Quantity 5 Crystal Raw Sapphire 7 5 Rock Chromium Ore 5 5 Rock Rhodite 5 5 Glowing Radium Ore 2 5 Rock Titanium Ore 1 4 Glowing Californium Ore 71 4 Glowing Ceresite 36 4 Glowing Saganite 35 4 Rock Silver Ore 26 4 Rock Galactic Ore 20 4 Rock Manganese Ore 20 4 Rock Anubium Ore 16 4 Rock Herculinium Ore 14 4 Crystal Raw Black Opal 14 4 Rock Raw Centauricite 14 4 Crystal Raw Fire Opal 11 4 Crystal Raw Flawless Garnet 9 4 Rock Vanadium Ore 7 4 Crystal Raw Ruby 1 3 Glowing Barite 114 3 Glowing Calcite 104 3 Glowing Alanite 98 3 Glowing Polonium Ore 93 3 Glowing Boronite 78 3 Rock Indium Ore 64 3 Rock Tungsten Ore 61 3 Rock Gallium Ore 60 3 Rock Caesium Ore 55 3 Crystal Raw Malachite 55 3 Crystal Raw Lapis Lazuli 48 3 Rock Star Iron Ore 48 3 Rock Cobalite 42 3 Crystal Raw Citrine 38 3 Crystal Raw Alexandrite 32 2 Glowing Brominite 55 2 Rock Germanium Ore 52 2 Glowing Phosphates 51 2 Glowing Plutonium Ore 50 2 Glowing Cadmium Ore 38 2 Rock Zircon 37 2 Rock Tin Ore 29 2 Rock Magnesium Ore 28 2 Rock Aluminium Ore 26 2 Crystal Raw Tourmaline 22 2 Crystal Raw Turquoise 21 2 Rock Hermesite 18 2 Rock Molybdenum Ore 14 2 Crystal Raw Amethyst 12 2 Crystal Raw Sunstone 8 2 Crystal Raw Moonstone 5 2 Crystal Raw Garnet 4 1 Glowing Sulfates 9 1 Glowing Uranium Ore 9 1 Crystal Raw Onyx 7 1 Crystal Diridium Crystal 5 1 Glowing Lithium Ore 4 1 Rock Lead Ore 3 1 Glowing Potash 3 1 Crystal Raw Agate 2 1 Rock Crude Nickel 1 1 Rock Iron Ore 1 1 Rock Magnetite Ore 1
  12. edit: Also, shameless plug (since some ppl had asked) ^^Makes the account vault click-to-select instead of drag and drop, also adds filters. Huge time saver when you're moving around as much ore and Hulk stuff as I do 😛 I actually managed to mine out the gas fields in Glenn! Someone else was mining the normal roids so I didn't get a full sector mine out, but that's fine, I can get the rest later. But yeah: That's what the gas fields look like. Each of the little 'clusters' you see are one 'field' and represents probably 20 clouds stacked vertically /near each other. I am roughly counting 12 individual fields there. Oh, and the respawn is so fast that as I was clearing the bottom, it had already respawned to the middle hidden nav. o.0 Basically an infinite supply of 8 Gas Boragon 253 8 Gas Yunieon Gas 208 7 Gas Vaneon 202 8 Gas Emperion 190 7 Gas Wexeon 190
  13. Compare https://www.net-7.org/wiki/index.php?title=Carpenter to https://imgur.com/PBiHmcn That's just beautiful. And it makes it FAR more clear that at Lagrange Point 4: 3 hydrocarbon fields, 1 rock field (probably 2 though) and the hulks are hidden under the other roids, but they are there. Also, comparing the mining summary from the run in the wiki to the one I got just a couple hours ago, it's clear that my initial hypothesis, that certain sectors are better than others for minerals, appears to be false. Carp has a lot of lvl 5 hydrocarbons, so instead of getting mostly Andromesite, I got mostly Hades Blood. In the entire game, there are only 3 possible lvl 5 Hydrocarbon drops (andro, hades, and brood oil). So them swapping around makes sense. It also means Carp appears not to drop brood oil at all. Also, I knew I'd have to make zoom work at some point, but it's looking like I need to make zoom work sooner rather than later. *sigh* I think I'll collect more data first. Collecting data is fun, bashing on javascript and getting the web page to behave is...tedious. It's not as simple as just setting transform and scale on the div. All those little colored squares are in a 2d canvas object, so I need to scale that as well. I think I'll aim to have it work a bit like google earth; scroll wheel to zoom, click-and-drag to move around. Conclusions: I really do have to put some thought and effort into how to average results across multiple clears. *sigh* I was not looking forward to that. I enjoy mining, but that's...probably a bit much. "Let us help!" you'd need to: Create a private channel Press ctrl-t before mining every roid If it's a hulk, manually type in the hulk level before pressing ctrl-t (so, chat would be like: 5 Target 'Hulk' (X, Y, Z) || for a level 5 hulk) I did look into OCRing the screen or using autohotkey ImageMatch. Basically...too tedious. Mine out the entire roid (no cherry picking of any kind) Mine out every field before it has a chance to start respawning Mine out every field in the sector (this can be done over multiple sessions, so long as you do not re-mine a field). Meta: This is a lot for almost anyone to do, plus I'd have to trust the data was gathered correctly...it's...too much. I'll do it myself. Some sectors will be better places than others to find given materials. Not all materials will drop in all sectors, despite the level and roid type indicating they should. Also, Hull Evolution is a major factor in pop rock damage. I have 5 TTs and 1 JE in my mining fleet, block formation. One TT is still on his lvl 100 hull, the others all have their 135 hulls, all have lvl 8 shields, but the lvl 100 hull takes almost 2x as much damage from any given poprock as the other characters. They all have identical gear and are within 100m of the roid. Distance *is* a factor in pop rock damage, but the damage increase I'm seeing happens at all angles (where that lvl 100 hull char is closer/farther based on his group position). So what I am seeing is 100% to do with the hull evolution, and not purely distance. I'll be putting this in the wiki shortly.
  14. Since I'm almost out of forum storage, here are some photos showing progress. Posting here gave me the kick in the butt to start working on it some more I guess. https://imgur.com/a/TqFsy9E This is not the final version of what I want to do with ore. Ideally I'd have circular/square/shaped overlays showing where fields are, clearly showing overlapping fields, with mouseovers showing contents in that field. I have the raw data to do all that, but it's considerably more work. And I find it best to collect all the roid data first, and figure out how to define the fields once I have a better idea of all the various edge cases. The raw data is in the database would allow you to mark out where level 5-6 rock-type roids are, for example, but right now, the display doesn't show that. This is not the final form I desire, but rather, just showing what's possible. There is no way to automatically know where a given field is. The only way to figure that out is to mine out very methodically, listen for a field clear bonus, and enter that manually. That would make it possible to have an 'area' calculation wherein you could query all the roids in the sector or within a given X/Y/Z coordinate bounds, then parse through to see if they are part of your desired field, summing up the field drop totals along the way. "Dear god, why?!" Because then you'd be able to see "Oh, almost all of the Titanium comes from these 2 fields" or "Here's where to find Tiberium", etc. Also, the data entry method does not support multiple passes through the same zone. So if I went through Inverness a second time, logging again, it would not average the data correctly; it'd just (roughly) double everything that's already there. Also, if you cherry-pick fields (meaning you only mine some fields and not others) it wouldn't handle that either. Basically, just an FYI that there's a lot of work on those problems needed if someone wants to make a thottbot clone. As for the sector summary, push once to display it, and again to hide it. It only queries the server 1 time to get the data, and keeps it cached until you switch sectors. I will be updating the main post with an updated tarball and parse script shortly.
  15. So...moving in any way? There is so much that can be said, but it's all off topic. And, fundamentally, pointless. Pointless until we go down a road everyone knows we need to take, and nobody (sane) wants to go down. sigh.
  16. I found the normal HDR shader to be more appealing than MagicHDR, but that's the point of Reshade, preference. Notes: If you have any autohotkey scripts based on Pixel/Image/color matching, these shaders WILL break that. Create a preset with no shaders so you can use your scripts without tweaking. You can change shaders on the fly in 1-2 seconds. Some shaders are more intense than others, so if you feel like your game is chugging, it's probably the shader(s) you picked. How 'heavy' a shader is depends entirely on what it is doing and varies wildly shader to shader. Try and find out. The FPS limit cut my client CPU usage about in 1/2. I recommend limiting it to 120FPS, even if you have a 60hz panel, because input speed seems limited by frame rate, so autohotkey will input much slower at 60FPS than you're used to.
  17. I've used reshade in FF14 to make it more beautiful. Is there any meaningful beauty to be extracted from this game? Before/after screenshots maybe? (my of my 2MB is taken up with my projects, like the tampermonkey script, map tool/files, etc).
  18. Yeah, the math ended up being not that hard, I just had to think about it for a minute. Instead of const x_scale_factor = (viewport_width - (sector_list_width + 30)) / (xmax*2); const y_scale_factor = (viewport_height - (sector_name_rect.bottom + sector_name_bottom_margin)) / (ymax*2); You do const x_scale_factor = (viewport_width - (sector_list_width + 30)) / (xmax - xmin); const y_scale_factor = (viewport_height - (sector_name_rect.bottom + sector_name_bottom_margin)) / (ymax - ymin); So. not that hard. I was just irritated and not thinking. "How do you see them" You need to fly within 3-5km of them. Each has a slightly different discovery range (some are visible from 30+km, but that's rare) but generally you have to fly within about 4km of a hidden nav for it to become 'visible' on your screen (NOT on the map!) and then you can warp to it and 'discover' it. I think just getting within 4k is enough to make it target-able from any range via the X key in-game. Hidden navs never show up on the map. That's what makes them hidden. I think the Westwood dev's original idea was that people couldn't just share screenshots of where stuff was, to make people have to discover things themselves. You have to remember, the internet was very early when this game came out, most people who had been playing games for the past 20 years had written down notes for their own use, and discovered everything themselves. Most people didn't call the Nintendo hotline for tips, for example. In the years since, places like Thottbott and Wowhead have made it clear that the extreme majority of players LOVE being able to look up where to go and what to do, and the few people who want that old-school discovery can best be served by just...ya know, not going to wowhead. So, if designing a new game, the basic loop is: Create content with enough mystery to engage those who enjoy mystery. Make that content easy to data log/capture in an automated fashion Allow external websites to host data repositories of your content, where it is, how to do it, etc. In this way, everyone is happy, and you aren't burdened with needing to create and maintain that knowledge repo. Eve Online has the Eve University Wiki, WoW has wowhead (and Thottbot before that), there's wikia/fandom for most RPG games, you get the idea. Factorio is an example of maintaining the data yourself, as the game company. They have their official wiki which is automatically updated via scripts as they change game elements. That's quite rare though, and they spent a LOT of time getting that automation to work and create pages for things. Especially in the modding space.
  19. For Sector data: Look at the script I pasted. It keeps track of what sector you're in via the "Now entering <sector>" line. That's how you keep track of that. For roids: you need to either OCR, image match, or otherwise determine the tech level of the roid. If the emulator wasn't made of lies, then you could just infer that from the highest level ore in the roid (tech 4 roids should always have at least 1 tech 4 ore!). But it becomes a mess of data quickly when you have tech 3 ores dropping and you don't know if they came from legit tech 3 rocks (meaning tech 2 is possible) or from tech 4 rocks (meaning the emulator is a lying sack of shit). So OCR/manual/image match are the only viable strategies. It'd be a simple AHK loop: Push trigger button image match text to get tech level send commands to game client to write manual text like '5' (for a tech 5 roid) to chat send 'ctrl+t' to game client to get it to dump roid position Have your python script keep track of state and associate that ores A and B came out of a tech 5 roid of <type>. This does NOT solve the problem you just finished dealing with on the wiki where both glowing and rock asteroids are called 'asteroid'. Another option is to write a simple C++ voice recognition program which would allow you to simply say "glowing 5" and then mine the rock (assuming the program could write 'glowing 5' to the private channel). I tried doing this, but it's been too many years since I worked with the MS Speech APIs and I don't feel like installing Visual Studio or some other C++ environment on my PC. I tried compiling with cygwin and it was just a PITA. For damage by mob: Correct. This one is always going to be manual, but flying around and poking each mob with 1 shot isn't *that* bad. It gets a bit dicey once you get into the higher level mobs (50+) that really hurt, but maybe someone will run shadowplay or OBS and just record their screen and type it in after the fact. I do agree, some combat logging would be super helpful for automation. If you wanted to go the wowhead path, just write a piece of code that intercepts the packets between the Net7Proxy and the game client. The encryption keys are known, so decrypting the packets is simple, once you can inject yourself into that link. As for what each packet opcode does, find the source cold for the old emulator, the opcodes cannot change as they are hard-coded into the client. That's the 'proper' way to write a wowhead client. But, again, why? The same frustrations that drove me away are the reason I don't feel like writing that. It wouldn't be an accomplishment, it'd be a waste of time.
  20. So, I'm semi-abandoning a project I started but am probably not going to finish anytime soon. But I dumped enough hours into it, and feel it has enough merit, that I am going to share the source code in case someone else thinks this is cool and wants to work on it. What is it? A replacement for enbmaps.de and all the other mapping sites we have. I wanted it to show where mobs spawned, and where roid fields were, along with the mining results from every zone (see the wiki on pages like Glenn, to see what I mean by 'mining results', the list of ores found in each sector). Right now, I have all the sectors and all the navs (that I could find) imported. Look in the 'initialization data' folder. No mobs/roids/gravity wells have been added yet. The annoyance of logging ore fields in a way that didn't drive me nuts (and the tedium of logging mobs) made me not want to bother...for about 2 weeks now. "What's the license" You may not use this software for commercial gain. No ads, no donations, no other revenue streams. If you break even with hosting and publicly (no request, publicly, on a normal page anyone can view) display that your operating it as non-profit, that's fine. It must remain open source in its entirety. Every image, every line of code, every byte of data in the database must all be accessible without authorization or signup. The code cannot be placed on github or any other site which intends to ingest the code into AI tools or otherwise monetize the code hosted there. Running your own git instance and hosting from there is fine. Any future license must require and honor these terms. Meaning, you cannot repackage this and change the license to MIT or something else. These terms of license must be in all downstream forks. For running a production site For an actual production site, you'll probably want to use mysql instead of sqlite, but sqlite is great for development and the code changeover from one to the other isn't bad. Mostly it's replacing ? with %s in a bunch of places. Well...the binding process is completely different, but meh. I didn't write it using mysql, again, if zen4's Promontory 21 hadn't been the shitshow it was, I'd have written it to use mysql. Also, you'll probably want to remove the Command Bar entirely from a production site. This tool wasn't really built to work like a wiki. It was meant for 1-2 people who are highly trusted to update the DB, then for it to mostly be a read-only experience. The idea behind adding mobs: Fly around with two chars. A JD and a PW are optimal. JD has 3 beams, 1 Energy, 1 EMP, 1 Plasma. PW has 3 guns, one loaded Explosive, 1 loaded Impact, 1 loaded Chemical. Telescopium on the JD DO NOT USE ANY RESIST DEBUFFS OF ANY KIND! Not even gravity link. Click on the 'Add Mob' button, shoot with energy laser, say it does 145 (-50) damage. You'd type in 145 for the Damage Component and -50 for the Resist Component. There's a blub on the page that explains all this. Fire 1 round from all the other weapon types and enter the damage/resist components. For positive numbers just enter the number without a + sign, so +500 is just 500. The page is smart enough to know that 145 (-50) meant you did 195 dmg, and 1000 (+500) meant you did 500. The page will do the math on its own to determine the mob resists and store them in the DB. A checkbox needs to be added for whether or not the mob is default hostile. "All this is in the wiki!" Yeah, but seeing it on a map is easier, and for things like mobs and ore, it helps to visually see where things are. Sure, there's Titanium in KV, but *where* in KV. Oh, only 2-3 of the 17 fields there. Cool. Now I know where to warp. "This javascript is written by a moron" Yeah. this is my first major javascript attempt. I was making this a web 2.0 page (so, one page load, then only DOM changes after) purely for practice/learning. You'll note I don't import jquery or any libraries. This is all hand-written baisc javascript. Maybe I'm a masochist. Maybe I just like learning. *shrug* "How did you get the navs?" Log into the game (ON ONE CHARACTER, DO NOT MULTIBOX FOR THIS unless using separate installs), enter a sector, Create a private channel (mostly to avoid spamming others) Target a 'normal' nav, press ctrl+t (I remapped it to b for easier pressing) Press n to go to the next visible nav Press ctrl+t Repeat until all visible navs are reported in chat. Don't worry about duplicates, the code below is smart enough to remove them. type 'hidden' in your private channel press 'x' to target the nearest hidden nav (move away if asteroids are in view) Press ctrl+t Press n to go to the next hidden nav Repeat until all hidden navs are dumped Close game Run script below on your chat.log file Copy-paste output into the "Add Navs" button, after you check the 'JSON Import' checkbox I imagine a script similar to this will be useful for import mobs/roids from chat as well. I did not do the work to make this a thing though. Also, I did not learn sectors could be asymmetric (like Grissom, where it's box is -450|575|-525|650) until I was almost done adding sectors, so roughly 40 of the 69 sectors in the game should be double-checked for asymmetry. sector_ids 1-53 are suspect, basically. Xipe Totec was the first asymmetric zone I remember finding. After Xipe, I made sure to check all 4 dimensions instead of assuming symmetry. --Parse_navs.py-- #!/usr/bin/python3 import argparse import json import re """THis list is also defined in functions.php and map_script.js, update all 3! $NAV_TYPE_MAP_BASE = [ "Normal Nav" => 0, "Hidden Nav" => 1, "Normal Gate" => 2, "Faction Gate" => 3, "Normal Station" => 4, "Faction Station" => 5, "Planet" => 6, "Landable Planet" => 7, "Weft" => 8, "Extended Weft" => 9, "Ore Field" => 10 ]; """ def parse_log(file_path, channel_name, player_name): results = {} sector_pattern = re.compile(r"We have entered (.+?) Sector \((.+?)\)") target_pattern = re.compile(r"\[(\d+)\] " + re.escape(player_name) + r": Target '(.+?)' at \(([-\d.]+), ([-\d.]+), ([-\d.]+)\)") hidden_nav_pattern = re.compile(r"\[(\d+)\] " + re.escape(player_name) + r": hidden") current_sector = "" hidden_nav_mode = False with open(file_path, 'r', encoding='latin-1') as file: for line in file: sector_match = sector_pattern.search(line) if sector_match: sector_name = sector_match.group(1) system_name = sector_match.group(2) current_sector = sector_name #print(f"We have entered {sector_name} ({system_name})") hidden_nav_mode = False if hidden_nav_pattern.search(line): hidden_nav_mode = True target_match = target_pattern.search(line) if target_match: target_channel = target_match.group(1) target_name = target_match.group(2) nav_type = 0; if target_name.startswith("Sector Gate ") or target_name.startswith("Accelerator") or target_name.startswith("System Gate"): nav_type = 2; if hidden_nav_mode: nav_type = 1 if target_channel == channel_name: x_coord = int(round(float(target_match.group(3)),0)) y_coord = int(round(float(target_match.group(4)),0)) z_coord = int(round(float(target_match.group(5)),0)) if current_sector not in results: results[current_sector] = {} #Assume normal navs until we have some way to mark other things automatically. coord_pack = [x_coord, y_coord, z_coord, nav_type] if target_name not in results[current_sector]: results[current_sector][target_name] = [coord_pack] elif coord_pack not in results[current_sector][target_name]: results[current_sector][target_name].append(coord_pack) #print(f"Target '{target_name}' at ({x_coord}, {y_coord}, {z_coord}, {nav_type})") #print(json.dumps(results, indent=4)) #print(results) print(format_output(results)) def format_output(data): formatted_output = "{" for key in data: formatted_output += f'"{key}": {{\n' for nav in data[key]: formatted_output += f'\t"{nav}": {data[key][nav]},\n' formatted_output = formatted_output[:-2] + "},\n" # Remove the trailing comma and newline character for the last line formatted_output = formatted_output[:-2] + "}\n" return formatted_output if __name__ == "__main__": parser = argparse.ArgumentParser(description="Parse log file") parser.add_argument("file", help="Path to the log file") parser.add_argument("--channel", default="100", help="Channel name (default: [100])") parser.add_argument("--player", default="Doctorje", help="Player name (default: Doctorje)") args = parser.parse_args() parse_log(args.file, args.channel, args.player) --parse_ores.py-- #!/usr/bin/python3 import argparse import json import re import sqlite3 import sys RESOURCE_SOURCE_MAP = { "Copper Ore": ["Rock", 1], "Crude Graphite": ["Hydrocarbon", 1], "Crude Nickel": ["Rock", 1], "Diridium Crystal": ["Crystal", 1], "Hydrogen": ["Gas", 1], "Iron Ore": ["Rock", 1], "Lead Ore": ["Rock", 1], "Lithium Ore": ["Glowing", 1], "Magnetite Ore": ["Rock", 1], "Mordanite": ["Rock", 1], "Nitrogen": ["Gas", 1], "Oxygen": ["Gas", 1], "Potash": ["Glowing", 1], "Raw Agate": ["Crystal", 1], "Raw Beryl": ["Crystal", 1], "Raw Black Tazeron": ["Hydrocarbon", 1], "Raw Bloodstone": ["Crystal", 1], "Raw Blue Tazeron": ["Hydrocarbon", 1], "Raw Crude Coal": ["Hydrocarbon", 1], "Raw Green Tazeron": ["Hydrocarbon", 1], "Raw Jasper": ["Crystal", 1], "Raw Onyx": ["Crystal", 1], "Raw Red Tazeron": ["Hydrocarbon", 1], "Raw Topaz": ["Crystal", 1], "Raw White Tazeron": ["Hydrocarbon", 1], "Raw Yellow Tazeron": ["Hydrocarbon", 1], "Sand": ["Hydrocarbon", 1], "Sponge Chloride": ["Crystal", 1], "Sulfates": ["Glowing", 1], "Tar": ["Hydrocarbon", 1], "Uranium Ore": ["Glowing", 1], "Zinc Ore": ["Rock", 1], "Aluminium Ore": ["Rock", 2], "Brominite": ["Glowing", 2], "Cadmium Ore": ["Glowing", 2], "Carbon Dioxide": ["Gas", 2], "Crude Oil": ["Hydrocarbon", 2], "Germanium Ore": ["Rock", 2], "Helium": ["Gas", 2], "Hermesite": ["Rock", 2], "Magnesium Ore": ["Rock", 2], "Methane": ["Gas", 2], "Molybdenum Ore": ["Rock", 2], "Phosphates": ["Glowing", 2], "Plutonium Ore": ["Glowing", 2], "Quartz Crystals": ["Hydrocarbon", 2], "Raw Amethyst": ["Crystal", 2], "Raw Coal": ["Hydrocarbon", 2], "Raw Garnet": ["Crystal", 2], "Raw Moonstone": ["Crystal", 2], "Raw Sunstone": ["Crystal", 2], "Raw Tourmaline": ["Crystal", 2], "Raw Turquoise": ["Crystal", 2], "Tin Ore": ["Rock", 2], "Zircon": ["Rock", 2], "Alanite": ["Glowing", 3], "Barite": ["Glowing", 3], "Boronite": ["Glowing", 3], "Caesium Ore": ["Rock", 3], "Calcite": ["Glowing", 3], "Cobalite": ["Rock", 3], "Fluorine": ["Gas", 3], "Gallium Ore": ["Rock", 3], "Indium Ore": ["Rock", 3], "Light Crude Oil": ["Hydrocarbon", 3], "Obsidian": ["Hydrocarbon", 3], "Polonium Ore": ["Glowing", 3], "Raw Alexandrite": ["Crystal", 3], "Raw Anthracite": ["Hydrocarbon", 3], "Raw Citrine": ["Crystal", 3], "Raw Lapis Lazuli": ["Crystal", 3], "Raw Malachite": ["Crystal", 3], "Star Iron Ore": ["Rock", 3], "Tungsten Ore": ["Rock", 3], "Anubium Ore": ["Rock", 4], "Argon": ["Gas", 4], "Californium Ore": ["Glowing", 4], "Ceresite": ["Glowing", 4], "Galactic Ore": ["Rock", 4], "Herculinium Ore": ["Rock", 4], "Manganese Ore": ["Rock", 4], "Meteoric Sand": ["Hydrocarbon", 4], "Neon": ["Gas", 4], "Raw Black Opal": ["Crystal", 4], "Raw Centauricite": ["Rock", 4], "Raw Fire Opal": ["Crystal", 4], "Raw Flawless Garnet": ["Crystal", 4], "Raw Ruby": ["Crystal", 4], "Saganite": ["Glowing", 4], "Silver Ore": ["Rock", 4], "Solar Sweet Oil": ["Hydrocarbon", 4], "Vanadium Ore": ["Rock", 4], "Andromesite": ["Hydrocarbon", 5], "Bastinium Ore": ["Glowing", 5], "Brood Oil": ["Hydrocarbon", 5], "Chromium Ore": ["Rock", 5], "Gold Ore": ["Rock", 5], "Hades Blood": ["Hydrocarbon", 5], "Halon": ["Gas", 5], "Hawkinsite": ["Glowing", 5], "Minervite": ["Glowing", 5], "Radium Ore": ["Glowing", 5], "Radon": ["Gas", 5], "Raw Black Pearl": ["Crystal", 5], "Raw Capellicite": ["Crystal", 5], "Raw Heartstone": ["Crystal", 5], "Raw Sapphire": ["Crystal", 5], "Raw Skystone": ["Crystal", 5], "Rhodite": ["Rock", 5], "Titanium Ore": ["Rock", 5], "Zalmoxium Ore": ["Rock", 5], "Adamantine Ore": ["Rock", 6], "Charon's Dust": ["Hydrocarbon", 6], "Curium Ore": ["Glowing", 6], "Discordite": ["Glowing", 6], "Hafnium Ore": ["Rock", 6], "Homerite": ["Rock", 6], "Krypton": ["Gas", 6], "Mirandium Ore": ["Rock", 6], "Osirium Ore": ["Rock", 6], "Oxium Ore": ["Rock", 6], "Platinum Ore": ["Rock", 6], "Raw Anthenicite": ["Hydrocarbon", 6], "Raw Charon Crystal": ["Glowing", 6], "Raw Emerald": ["Crystal", 6], "Raw Flawless Ruby": ["Crystal", 6], "Raw Icy Pearl": ["Crystal", 6], "Stygian Blackwater": ["Hydrocarbon", 6], "Xenon": ["Gas", 6], "Apollonite": ["Glowing", 7], "Brucite Ore": ["Glowing", 7], "Celestial Ore": ["Rock", 7], "Chalcophanite": ["Glowing", 7], "Conorite": ["Rock", 7], "Cupidite": ["Glowing", 7], "Demeter's Tears": ["Hydrocarbon", 7], "Horusium Ore": ["Glowing", 7], "Inderite": ["Rock", 7], "Iridium Ore": ["Rock", 7], "Leonite": ["Hydrocarbon", 7], "Neutronium Ore": ["Glowing", 7], "Niobite": ["Rock", 7], "Raw Barite": ["Glowing", 7], "Raw Diamond": ["Crystal", 7], "Raw Eye Stone": ["Crystal", 7], "Raw Firerock": ["Crystal", 7], "Raw Galactic Rimstone": ["Crystal", 7], "Raw Hadecite": ["Hydrocarbon", 7], "Stojsavline": ["Gas", 7], "Stygian Blacksand": ["Hydrocarbon", 7], "Tantalum Ore": ["Rock", 7], "Vaneon": ["Gas", 7], "Wexeon": ["Gas", 7], "Abyssian Dust": ["Hydrocarbon", 8], "Ambrosia Crude": ["Hydrocarbon", 8], "Boragon": ["Gas", 8], "Duplium Ore": ["Rock", 8], "Emperion": ["Gas", 8], "Helvatha": ["Hydrocarbon", 8], "Idunium Ore": ["Rock", 8], "Khnumium Ore": ["Glowing", 8], "Minosium Ore": ["Glowing", 8], "Morganium Ore": ["Rock", 8], "Persephonite": ["Glowing", 8], "Pyrrhotite Gneiss": ["Hydrocarbon", 8], "Raw Acheronite": ["Hydrocarbon", 8], "Raw Alunite": ["Rock", 8], "Raw Charybdis Voidstone": ["Crystal", 8], "Raw Meteoric Diamond": ["Crystal", 8], "Raw Mica": ["Hydrocarbon", 8], "Raw Scyllan Diamond": ["Crystal", 8], "Raw Tincal": ["Rock", 8], "Raw Voidgem": ["Crystal", 8], "Vanirum Ore": ["Rock", 8], "Yunieon Gas": ["Gas", 8], "Abaddon Ashes": ["Hydrocarbon", 9], "Aesirium Ore": ["Rock", 9], "Asmodeusium Ore": ["Rock", 9], "Astralite": ["Hydrocarbon", 9], "Balderium Ore": ["Rock", 9], "Crude Rutha": ["Hydrocarbon", 9], "Etherion": ["Gas", 9], "Grail Water": ["Hydrocarbon", 9], "Kronosite": ["Glowing", 9], "Modredium Ore": ["Rock", 9], "Nova Dust": ["Crystal", 9], "Noxion": ["Gas", 9], "Pagion": ["Gas", 9], "Raw Erebusite": ["Hydrocarbon", 9], "Raw Promethium": ["Rock", 9], "Raw Star Ore": ["Rock", 9], "Raw Tiberium Crystals": ["Crystal", 9], "Raw Wormstone": ["Crystal", 9], "Star Ash": ["Crystal", 9], "Thothium Ore": ["Hydrocarbon", 9], "Troseki": ["Rock", 9], "Ziosite": ["Hydrocarbon", 9] } """ Error List: Raw Erebusite comes from Hydrocarbon, not Crystal Raw Charon Crystal comes from Glowing, not Crystal? """ """THis list is also defined in functions.php and map_script.js, update all 3! $NAV_TYPE_MAP_BASE = [ "Normal Nav" => 0, "Hidden Nav" => 1, "Normal Gate" => 2, "Faction Gate" => 3, "Normal Station" => 4, "Faction Station" => 5, "Planet" => 6, "Landable Planet" => 7, "Weft" => 8, "Extended Weft" => 9, "Ore Field" => 10 ]; """ def createDB(db_cur): sql = """CREATE TABLE raw_roids( roid_id INTEGER PRIMARY KEY, sector_name TEXT NOT NULL, x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL, source_type TEXT CHECK(source_type IN ('Rock','Glowing','Hydrocarbon','Crystal','Gas','Hulk')) NOT NULL, level INTEGER NOT NULL CHECK(level IN (1,2,3,4,5,6,7,8,9)))""" db_cur.execute(sql); sql = """CREATE TABLE raw_roid_contents( raw_roid_id INTEGER NOT NULL, roid_held TEXT NOT NULL, quantity INTEGER NOT NULL, FOREIGN KEY (raw_roid_id) REFERENCES raw_roids(roid_id) ON DELETE CASCADE)""" db_cur.execute(sql); def getNextID(db_cur, table_name, id_col_name): db_cur.execute(f"""SELECT IFNULL(MIN(t1.{id_col_name} + 1),1) AS next_available_id FROM {table_name} t1 LEFT JOIN {table_name} t2 ON t1.{id_col_name} + 1 = t2.{id_col_name} WHERE t2.{id_col_name} IS NULL;""") return db_cur.fetchone()[0] def addDataToDB(db_cur, roid_details, mining_details): #Check if the roid is already in the DB db_cur.execute("SELECT roid_id FROM raw_roids WHERE sector_name = ? AND x = ? AND y = ? AND z = ? AND source_type = ? AND level = ?", roid_details) row = db_cur.fetchone() roid_id = 0 if row: roid_id = row[0] else: roid_id = getNextID(db_cur, "raw_roids", "roid_id") final_roid_details = (roid_id,) + roid_details db_cur.execute('INSERT INTO raw_roids (roid_id, sector_name, x, y, z, source_type, level) VALUES (?,?, ?,?,?, ?,?)', final_roid_details) if mining_details: final_mining_details = (roid_id,) + mining_details db_cur.execute("INSERT INTO raw_roid_contents(raw_roid_id, roid_held, quantity) VALUES (?,?,?)", final_mining_details) #end addDataToDB def parse_log(file_path, channel_name, player_name): results = {} db_conn = sqlite3.connect(":memory:") #db_conn = sqlite3.connect("testing.db") db_conn.row_factory = sqlite3.Row db_cur = db_conn.cursor() createDB(db_cur) sector_pattern = re.compile(r"We have entered (.+?) Sector \((.+?)\)") target_pattern = re.compile(r"\[" + re.escape(channel_name) + "] " + re.escape(player_name) + r": Target '(.+?)' at \(([-\d.]+), ([-\d.]+), ([-\d.]+)\)") target_with_level_pattern = re.compile(r"\[" + re.escape(channel_name) + "] " + re.escape(player_name) + r": ([-\d.]+) Target '(.+?)' at \(([-\d.]+), ([-\d.]+), ([-\d.]+)\)") prospect_pattern = re.compile(r"COMPUTER: Prospected \(([-\d.]+)\) (.+?)$") roid_level_pattern = re.compile(r"\[(\d+)\] " + re.escape(player_name) + r": ([-\d.]+) Target '") current_sector = "" current_roid_level = 0 current_roid = None current_roid_ingame_type = None roid_contents = [] with open(file_path, 'r', encoding='latin-1') as file: for line in file: sector_match = sector_pattern.search(line) if sector_match: sector_name = sector_match.group(1) system_name = sector_match.group(2) current_sector = sector_name current_roid_level = 0 current_roid = None current_roid_ingame_type = None #print(f"We have entered {sector_name} ({system_name})") roid_level_match = roid_level_pattern.search(line) if roid_level_match: current_roid_level = roid_level_match.group(2) hulk_match = target_with_level_pattern.search(line) target_match = target_pattern.search(line) if (hulk_match or target_match) and current_roid is not None: if current_roid_ingame_type != 'Hulk': #Run through once to find max level ore in roid, but not for hulks. for contents in roid_contents: if current_roid[5] < RESOURCE_SOURCE_MAP[contents[0]][1]: current_roid[5] = RESOURCE_SOURCE_MAP[contents[0]][1] #and again to actually update db for contents in roid_contents: addDataToDB(db_cur, tuple(current_roid), contents) roid_contents = [] if hulk_match: target_level = hulk_match.group(1) target_name = hulk_match.group(2) x_coord = int(round(float(hulk_match.group(3)),0)) y_coord = int(round(float(hulk_match.group(4)),0)) z_coord = int(round(float(hulk_match.group(5)),0)) current_roid = [sector_name, x_coord,y_coord,z_coord, target_name, target_level] current_roid_ingame_type = target_name if target_match: target_name = target_match.group(1) x_coord = int(round(float(target_match.group(2)),0)) y_coord = int(round(float(target_match.group(3)),0)) z_coord = int(round(float(target_match.group(4)),0)) current_roid = [sector_name, x_coord,y_coord,z_coord, None, 0] current_roid_ingame_type = target_name prospect_match = prospect_pattern.search(line) if prospect_match and current_roid is not None: quantity = prospect_match.group(1) ore_name = prospect_match.group(2) if ore_name in RESOURCE_SOURCE_MAP: roid_type = RESOURCE_SOURCE_MAP[ore_name][0] roid_type_ingame = "" if roid_type == "Rock" or roid_type == "Glowing": roid_type_ingame = "Asteroid" elif roid_type == "Crystal": roid_type_ingame = "Crystalline Asteroid" elif roid_type == "Gas": roid_type_ingame = "Gas Cloud" elif roid_type == "Hydrocarbon": roid_type_ingame = "Hydrocarbon Deposit" else: roid_type_ingame = roid_type if current_roid_ingame_type != roid_type_ingame: print(f"INVALID SOURCE ERROR: {current_roid} has contents {ore_name} which should come from {roid_type} type roids.") sys.exit(1) current_roid[4] = roid_type roid_contents.append((ore_name, quantity)) db_conn.commit() db_cur.execute("Select * from raw_roids LEFT JOIN raw_roid_contents on roid_id = raw_roid_id") rows = db_cur.fetchall() the_json = dict() prev_roid_id = None for row in rows: # sys.stdout.write("DEBUG: ") # for data in row: # sys.stdout.write(f",{data} ") # sys.stdout.write("\n") if row['sector_name'] not in the_json: the_json[row['sector_name']] = dict() if row['source_type'] not in the_json[row['sector_name']]: the_json[row['sector_name']][row['source_type']] = [] roid_details = { "level": row['level'], "coords": [row['x'],row['y'],row['z']] } if row['roid_held'] is not None: if 'contents' not in roid_details: roid_details['contents'] = dict() roid_details['contents'][row['roid_held']] = row['quantity'] if row['roid_id'] != prev_roid_id: the_json[row['sector_name']][row['source_type']].append(roid_details) else: if row['roid_held'] in the_json[row['sector_name']][row['source_type']][-1]['contents']: the_json[row['sector_name']][row['source_type']][-1]['contents'][row['roid_held']] += row['quantity'] else: the_json[row['sector_name']][row['source_type']][-1]['contents'][row['roid_held']] = row['quantity'] prev_roid_id = row['roid_id'] #print(json.dumps(the_json, indent=4)) print(json.dumps(the_json)) #print(the_json) #print(format_output(the_json)) def format_output(data): formatted_output = "{" for sector in data: formatted_output += f'"{sector}": {{\n' for roid_type in data[sector]: formatted_output += f'\t"{roid_type}": [\n' for inner_data in data[sector][roid_type]: formatted_output += f'\t\t{{\n' for key in inner_data: formatted_output += f'\t\t\t"{key}": {inner_data[key]},\n' formatted_output = formatted_output[:-2] + "\n\t\t},\n" formatted_output = formatted_output[:-2] + "\n\t],\n" formatted_output = formatted_output[:-2] + "\n},\n" # Remove the trailing comma and newline character for the last line formatted_output = formatted_output[:-2] + "}\n" formatted_output = formatted_output.replace("'",'"') return formatted_output if __name__ == "__main__": parser = argparse.ArgumentParser(description="Parse log file") parser.add_argument("file", help="Path to the log file") parser.add_argument("--channel", default="100", help="Channel name (default: [100])") parser.add_argument("--player", default="Doctorje", help="Player name (default: Doctorje)") args = parser.parse_args() parse_log(args.file, args.channel, args.player) "How do I initialize this project?" I assume you are on linux and can get a basic PHP running on your own. sqlite3 better_map.db .read initialization_data/base_schema.sqlite_3 .read initialization_data/3_10_data_import.sql cat initialization_data/mining_data_1 Press "Add Ores", paste in the JSON, submit. cat initialization_data/mining_data_2 Press "Add Ores", paste in the JSON, submit. Edit get_missing_item.php and put in your net-7 username/password. Yes I know that 'isn't secure'. This is a one-person app that I'm likely to be the only user of. It's fine for that. If you do it 'for real', then make it better. Only needed if you want it to auto-fetch missing items (from Hulks) that are not currently in your DB. You should be good to go. The sector_data files are there as backups, in case the 3_10 import fails for some reason, or if you want to debug/test the JSON nav import feature. 3_25_backup_for_distro.tar.gz
  21. That doesn't really work because Tarsis (the planet) is outside the bounds of the sector. Ragnarok as well. It's totally possible to have a nav outside the sector bounds when it is big enough to be seen from *within* the sector bounds. Well, technically, each nav has a 'detection radius' field, so you could just set every nav to be detectable from 300km and all the navs would be discovered the second you gated in. But that's obviously a bad idea. I'm saying that the client/server logic allows for this.
  22. Just to illustrate visually how massive some of these sectors are compared to the navs in them (the white box is the in-game sector bounds, the navs are scaled correctly relative to the size of the white box): And, to show that not *every* sector is like this, here's a sector that's sized according to the navs within it: Side-note: I now appreciate how much work went into enbmaps.de because holy balls this is a lot of fiddling and tweaking. My maps are still very much a WIP. I plan to add overlays for mobs and ore, and filters to let you control name opacity (right now if you mouse over a nav the name becomes fully visible, but that's hard to screenshot) and scale. But I'm still at stage 3 or 4, where I'm going around collecting all the nav points in the game.
  23. Why is Saturn so huge? It is 1176km tall and 782km wide. Why? The navs occupy an area that would fit within a (roughly) 250x250km square. Jupiter, also, is a bit wonky, being 800km wide when it needs to be roughly 1/2 that. Almost all sectors are symmetrical in their axis (meaning -588km in -X to 588km in +x, but the same sector can have a different Y, but Y is also symmetrical, so -188y and +188y, but X can be different). Except for (so far): X: (min, max) || Y: (min, max) Kitara's Veil: X: -157,157 || y: -75, 172 Kailaasa: X: -188, 529 || y: -149, 490 I found these while building a replacement for enbmaps. Mine is still very much in development. But these make no sense. So, I guess I have two fundamental questions: Why are some sectors 5x the size they need to be when there is nothing in the empty space? Or is there something there, and I'm going to have to do the most anal-retentive of box-searches using 4 characters and scanning lines 4km apart (since we can't detect hidden navs from > than about 3-4km) to find the one hidden nav somewhere in the middle of all that nothing? I was going to do the box searches anyway, it just makes it 100x more annoying. Why can't all the systems just have a symmetrical size? It makes the math to convert coordinate systems so much more annoying.
  24. Looks like a bug with all MLs to me. I see the same behavior in Type Bs (lvl 4-6) and Type As (lvl 7-9). Projectiles seem fine. The search results are assuming a 37% reduction in reload time, while the item pages are assuming a 35% reduction in reload time. This is not the case with projectiles, where both assume a 37% reload time reduction at 200%. How or why this is the case? Only a web dev can answer that.
  25. Win 10 is the reason my next PC is going to be Linux. Just holding out for zen5... (and I woulda built zen4 if I had known 5 was going to reuse that stupid-ass Promontory 21 chipset that only has 4x PCIe4.0 lanes instead of the PCIe5 lanes the CPU *actually* has for the chipset! grr!). Win 7 was the last 'ok' OS IMO.
×
×
  • Create New...