/* Copyright 2016-2017 sub1to This file is part of subVersion GTA:O SC External Hack. subVersion GTA:O SC External Hack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. subVersion GTA:O SC External Hack is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with subVersion GTA:O SC External Hack. If not, see . */ #include "stdafx.h" /* //SETTINGS CLASS */ settings::settings() { m_iniParser.m_szFile = "settings.ini"; m_iniParser.read(); //keys m_iKeys[keyExit] = strToVk(m_iniParser.getValue("Exit", "Keys")); m_iKeys[keyMenu] = strToVk(m_iniParser.getValue("Menu", "Keys")); m_iKeys[keyMenuUp] = strToVk(m_iniParser.getValue("MenuUp", "Keys")); m_iKeys[keyMenuDown] = strToVk(m_iniParser.getValue("MenuDown", "Keys")); m_iKeys[keyMenuLeft] = strToVk(m_iniParser.getValue("MenuLeft", "Keys")); m_iKeys[keyMenuRight] = strToVk(m_iniParser.getValue("MenuRight", "Keys")); m_iKeys[keyMenuSelect] = strToVk(m_iniParser.getValue("MenuSelect", "Keys")); m_iKeys[keyMenuBack] = strToVk(m_iniParser.getValue("MenuBack", "Keys")); m_iKeys[keyMenuTabNext] = strToVk(m_iniParser.getValue("MenuTabNext", "Keys")); m_iKeys[keyMenuTabPrev] = strToVk(m_iniParser.getValue("MenuTabPrev", "Keys")); m_iKeys[keyMenuSave] = strToVk(m_iniParser.getValue("MenuSave", "Keys")); m_iKeys[keyHotTeleport] = strToVk(m_iniParser.getValue("HotTeleport", "Keys")); m_iKeys[keyHotWanted] = strToVk(m_iniParser.getValue("HotWanted", "Keys")); m_iKeys[keyHotHealth] = strToVk(m_iniParser.getValue("HotHealth", "Keys")); m_iKeys[keyHotAmmo] = strToVk(m_iniParser.getValue("HotAmmo", "Keys")); } settings::~settings() { for(int i = 0; i < MAX_MENU_FEATURES; i++) { if(m_pFeature[i]) delete m_pFeature[i]; } for(int i = 0; i < MAX_MENU_TABS; i++) { if(m_pFeatureCat[i]) delete m_pFeatureCat[i]; } } void settings::toggleMenu() { m_bMenuActive = !m_bMenuActive; return; } bool settings::isMenuActive() { return m_bMenuActive; } void settings::menuDown() { if(m_iActiveFeature + 1 < m_nFeatureCur) { m_iActiveFeature++; if (m_iActiveFeature == m_iFeatureCurDisplayOffset + MAX_MENU_FEATURES_DISPLAYED - MENU_FEATURE_SCROLL_PADDING) { int displayOffset = m_iActiveFeature - (MAX_MENU_FEATURES_DISPLAYED - 1 - MENU_FEATURE_SCROLL_PADDING); displayOffset = (displayOffset > m_nFeatureCur - MAX_MENU_FEATURES_DISPLAYED) ? m_nFeatureCur - MAX_MENU_FEATURES_DISPLAYED : displayOffset; displayOffset = (displayOffset < 0) ? 0 : displayOffset; m_iFeatureCurDisplayOffset = displayOffset; } } else { m_iActiveFeature = 0; m_iFeatureCurDisplayOffset = 0; } return; } void settings::menuUp() { if(m_iActiveFeature - 1 >= 0) { m_iActiveFeature--; if (m_iActiveFeature == m_iFeatureCurDisplayOffset + MENU_FEATURE_SCROLL_PADDING - 1) { int displayOffset = m_iActiveFeature - MENU_FEATURE_SCROLL_PADDING; displayOffset = (displayOffset > m_nFeatureCur - MAX_MENU_FEATURES_DISPLAYED) ? m_nFeatureCur - MAX_MENU_FEATURES_DISPLAYED : displayOffset; displayOffset = (displayOffset < 0) ? 0 : displayOffset; m_iFeatureCurDisplayOffset = displayOffset; } } else { m_iActiveFeature = m_nFeatureCur - 1; int displayOffset = m_nFeatureCur - MAX_MENU_FEATURES_DISPLAYED; displayOffset = (displayOffset < 0) ? 0 : displayOffset; m_iFeatureCurDisplayOffset = displayOffset; } return; } void settings::menuRight() { return this->getFeatureCur(m_iActiveFeature)->inc(); } void settings::menuLeft() { return this->getFeatureCur(m_iActiveFeature)->dec(); } void settings::menuTabRight() { while(m_pFeatureCur[0]->m_iCat < 0) this->menuBack(); m_pFeatureCat[m_iActiveCat]->m_iDisplayOffsetRet = m_iFeatureCurDisplayOffset; m_pFeatureCat[m_iActiveCat]->m_iActiveFeatureRet = m_iActiveFeature; if(m_iActiveCat + 1 < m_nFeatureCat) this->setActiveCat(m_iActiveCat + 1); else this->setActiveCat(0); m_iFeatureCurDisplayOffset = m_pFeatureCat[m_iActiveCat]->m_iDisplayOffsetRet; m_iActiveFeature = m_pFeatureCat[m_iActiveCat]->m_iActiveFeatureRet; return; } void settings::menuTabLeft() { while(m_pFeatureCur[0]->m_iCat < 0) this->menuBack(); m_pFeatureCat[m_iActiveCat]->m_iDisplayOffsetRet = m_iFeatureCurDisplayOffset; m_pFeatureCat[m_iActiveCat]->m_iActiveFeatureRet = m_iActiveFeature; if(m_iActiveCat - 1 >= 0) this->setActiveCat(m_iActiveCat - 1); else this->setActiveCat(m_nFeatureCat - 1); m_iFeatureCurDisplayOffset = m_pFeatureCat[m_iActiveCat]->m_iDisplayOffsetRet; m_iActiveFeature = m_pFeatureCat[m_iActiveCat]->m_iActiveFeatureRet; return; } void settings::menuSelect() { feat* feat = this->getFeatureCur(m_iActiveFeature); feat->toggle(); return; } void settings::menuBack() { if(m_pFeatureCur[0]->m_iParent >= 0) //if the buffer is filled with features that have a parent, not a category { featParent* parent = dynamic_cast(m_pFeature[m_pFeatureCur[0]->m_iParent]); if(parent->m_iCat < 0) this->fillFeatureCurBuffer(parent->m_iParent, FFB_PARENT); else this->fillFeatureCurBuffer(parent->m_iCat, FFB_CATEGORY); m_iFeatureCurDisplayOffset = parent->m_iDisplayOffsetRet; m_iActiveFeature = parent->m_iActiveFeatureRet; } else { toggleMenu(); } return; } int settings::addFeatureCategory(std::wstring name) { if(m_nFeatureCat >= MAX_MENU_TABS) //prevent buffer overflow return -1; m_pFeatureCat[m_nFeatureCat] = new featCat; m_pFeatureCat[m_nFeatureCat]->m_iId = m_nFeatureCat; m_pFeatureCat[m_nFeatureCat]->m_szName = name; m_nFeatureCat++; return m_nFeatureCat - 1; } int settings::addFeature(int cat, int parent, std::wstring name, featType type) { if( m_nFeature >= MAX_MENU_FEATURES || //buffer overflow (parent < 0 && m_pFeatureCat[cat] == nullptr) || //invalid cat (cat < 0 && (m_pFeature[parent] == nullptr || m_pFeature[parent]->m_type != feat_parent)) || //invalid parent (cat < 0 && parent < 0) || (cat > 0 && parent > 0)) //both cat and parent were provided return -1; switch(type) { case feat_toggle: m_pFeature[m_nFeature] = new feat; break; case feat_btn: m_pFeature[m_nFeature] = new featBtn; break; case feat_slider: m_pFeature[m_nFeature] = new featSlider; break; case feat_teleport: m_pFeature[m_nFeature] = new featTeleport; break; case feat_parent: m_pFeature[m_nFeature] = new featParent; break; } m_pFeature[m_nFeature]->m_iId = m_nFeature; m_pFeature[m_nFeature]->m_iCat = cat; m_pFeature[m_nFeature]->m_iParent = parent; m_pFeature[m_nFeature]->m_type = type; m_pFeature[m_nFeature]->m_szName = name; m_nFeature++; return m_nFeature - 1; } int settings::addFeature(int cat, int parent, std::wstring name, featType type, int index, float arg) { int id = this->addFeature(cat, parent, name, type); if (id < 0) return id; dynamic_cast(m_pFeature[id])->m_iIndex = index; dynamic_cast(m_pFeature[id])->m_fArg = arg; return id; } int settings::addFeature(int cat, int parent, std::wstring name, featType type, std::string iniKey) { int id = this->addFeature(cat, parent, name, type); if(id < 0) return id; m_pFeature[id]->m_szIniKey = iniKey; m_pFeature[id]->m_bOn = (bool) m_iniParser.getValue(iniKey, "FeatureToggle"); m_pFeature[id]->m_bRestored = (m_pFeature[id]->m_bOn) ? false : true; return id; } int settings::addFeature(int cat, int parent, std::wstring name, featType type, std::string iniKey, float min, float max) { int id = this->addFeature(cat, parent, name, type, iniKey); if(id < 0) return id; dynamic_cast(m_pFeature[id])->m_fMin = min; dynamic_cast(m_pFeature[id])->m_fMax = max; float v = m_iniParser.getValue(iniKey, "FeatureValue"); if(v <= max && v >= min) dynamic_cast(m_pFeature[id])->m_fValue = v; else { dynamic_cast(m_pFeature[id])->m_fValue = min; m_iniParser.setValue(iniKey, min, "FeatureValue"); } return id; } int settings::addFeature(int cat, int parent, std::wstring name, featType type, std::string iniKey, float min, float max, float mod) { int id = this->addFeature(cat, parent, name, type, iniKey, min, max); if(id < 0) return id; dynamic_cast(m_pFeature[id])->m_fMod = mod; return id; } int settings::addFeature(int cat, int parent, std::wstring name, featType type, std::string iniKey, teleType tpType) { if(tpType != tp_saved) return -1; int id = this->addFeature(cat, parent, name, type, iniKey); if(id < 0) return id; dynamic_cast(m_pFeature[id])->m_tpType = tpType; dynamic_cast(m_pFeature[id])->m_v3Pos.x = m_iniParser.getValue(iniKey + "_x", "Teleport"); dynamic_cast(m_pFeature[id])->m_v3Pos.y = m_iniParser.getValue(iniKey + "_y", "Teleport"); dynamic_cast(m_pFeature[id])->m_v3Pos.z = m_iniParser.getValue(iniKey + "_z", "Teleport"); dynamic_cast(m_pFeature[id])->m_szName += L" | " + StringToWString(m_iniParser.getValue(iniKey + "_name", "Teleport")); return id; } int settings::addFeature(int cat, int parent, std::wstring name, featType type, teleType tpType) { if(tpType == tp_saved) return -1; int id = this->addFeature(cat, parent, name, type); if(id < 0) return id; dynamic_cast(m_pFeature[id])->m_tpType = tpType; return id; } int settings::addFeature(int cat, int parent, std::wstring name, featType type, teleType tpType, float x, float y, float z) { if(tpType == tp_saved) return -1; int id = this->addFeature(cat, parent, name, type, tpType); if(id < 0) return id; dynamic_cast(m_pFeature[id])->m_v3Pos.x = x; dynamic_cast(m_pFeature[id])->m_v3Pos.y = y; dynamic_cast(m_pFeature[id])->m_v3Pos.z = z; return id; } int settings::updataFeature(int id, int cat, int parent, std::wstring name, featType type) { if (id >= MAX_MENU_FEATURES || //buffer overflow (parent < 0 && m_pFeatureCat[cat] == nullptr) || //invalid cat (cat < 0 && (m_pFeature[parent] == nullptr || m_pFeature[parent]->m_type != feat_parent)) || //invalid parent (cat < 0 && parent < 0) || (cat > 0 && parent > 0)) //both cat and parent were provided return -1; m_pFeature[id]->m_iId = id; m_pFeature[id]->m_iCat = cat; m_pFeature[id]->m_iParent = parent; m_pFeature[id]->m_type = type; m_pFeature[id]->m_szName = name; return id; } int settings::updataFeature(int id, int cat, int parent, std::wstring name, featType type, teleType tpType, float x, float y, float z) { if (tpType == tp_saved) return -1; int ret = this->updataFeature(id, cat, parent, name, type); if (ret < 0) return ret; dynamic_cast(m_pFeature[ret])->m_tpType = tpType; dynamic_cast(m_pFeature[ret])->m_v3Pos.x = x; dynamic_cast(m_pFeature[ret])->m_v3Pos.y = y; dynamic_cast(m_pFeature[ret])->m_v3Pos.z = z; return ret; } int settings::getFeatureCategoryCount() { return m_nFeatureCat; } featCat* settings::getFeatureCategory(int id) { if(id > m_nFeatureCat) return 0; return m_pFeatureCat[id]; } int settings::getActiveCat() { return m_iActiveCat; } int settings::setActiveCat(int cat) { if(cat > m_nFeatureCat) return 0; m_iActiveCat = cat; this->fillFeatureCurBuffer(cat, FFB_CATEGORY); return 1; } bool settings::fillFeatureCurBuffer(int id, BYTE flag) { //prevent race conditions while(!g_pSettings->lockFeatureCur()) Sleep(1); ZeroMemory(&m_pFeatureCur, sizeof(feat*) * MAX_MENU_FEATURES); //clear buffer m_nFeatureCur = 0; m_iActiveFeature = 0; m_iFeatureCurDisplayOffset = 0; for(int i = 0; i < m_nFeature; i++) //create a list of features from current category { if( (m_pFeature[i]->m_iCat == id && flag & FFB_CATEGORY) || (m_pFeature[i]->m_iParent == id && flag & FFB_PARENT)) { m_pFeatureCur[m_nFeatureCur] = m_pFeature[i]; m_nFeatureCur++; } } this->unlockFeatureCur(); return 1; } int settings::getFeatureCurCount() { return m_nFeatureCur; } feat* settings::getFeatureCur(int i) { if(i > m_nFeatureCur) return 0; return m_pFeatureCur[i]; } int settings::getFeatureCount() { return m_nFeature; } feat* settings::getFeature(int id) { if(id > m_nFeature) return 0; return m_pFeature[id]; } int settings::getActiveFeature() { return m_iActiveFeature; } bool settings::getFeatureCurLock() { return m_bFeatureCurLock; } bool settings::lockFeatureCur() { if(m_bFeatureCurLock) return false; m_bFeatureCurLock = true; return true; } bool settings::unlockFeatureCur() { m_bFeatureCurLock = false; return true; } int settings::getDisplayOffset() { return m_iFeatureCurDisplayOffset; } /* //FEATURE CLASSES */ feat::feat() {} feat::~feat() {} void feat::toggle() { m_bOn = !m_bOn; if(m_bOn) m_bRestored = false; if(m_szIniKey != "") g_pSettings->m_iniParser.setValue(m_szIniKey, (int) m_bOn, "FeatureToggle"); return; } void feat::inc() {} void feat::dec() {} featBtn::featBtn() {} featBtn::~featBtn() {} void featBtn::toggle() { (*g_pCBMap)[this->m_iIndex]->Exec(&this->m_fArg); } featSlider::featSlider() {} featSlider::~featSlider() {} void featSlider::inc() { float v = (m_fValue + ( (m_fMax - m_fMin) * m_fMod) ); if(v <= m_fMax) m_fValue = v; else m_fValue = m_fMax; g_pSettings->m_iniParser.setValue(m_szIniKey, m_fValue, "FeatureValue"); return; } void featSlider::dec() { float v = (m_fValue - ( (m_fMax - m_fMin) * m_fMod) ); if(v >= m_fMin) m_fValue = v; else m_fValue = m_fMin; g_pSettings->m_iniParser.setValue(m_szIniKey, m_fValue, "FeatureValue"); return; } featTeleport::featTeleport() {} featTeleport::~featTeleport() {} void featTeleport::toggle() { switch(m_tpType) { case tp_waypoint: g_pHack->teleportWaypoint(); break; case tp_objective: g_pHack->teleportObjective(); break; case tp_saved: case tp_static: g_pHack->teleport(m_v3Pos); break; } } featParent::featParent() {} featParent::~featParent() {} void featParent::toggle() { m_iActiveFeatureRet = g_pSettings->getActiveFeature(); m_iDisplayOffsetRet = g_pSettings->getDisplayOffset(); g_pSettings->fillFeatureCurBuffer(this->m_iId, FFB_PARENT); return; } /* //INI PARSER CLASS */ iniParser::iniParser(){}; iniParser::iniParser(std::string szFile) : m_szFile(szFile) {}; iniParser::~iniParser(){}; void iniParser::read() { std::ifstream file; file.open(m_szFile, std::ios::in); if (!file.is_open()) { MessageBoxW(nullptr, L"未找到settings.ini配置文件,请将压缩包中所有文件解压到同一目录!", L"subVersion加载失败", MB_OK | MB_ICONERROR); g_bKillAttach = true; killProgram(); return; } std::string szLine; int iSection = -1; std::regex regexSection("^\\[([A-Za-z0-9_]+)\\]$"), regexKey ("^([A-Za-z0-9_]+)=([A-Za-z0-9_\\-*/+.\\s]+)$"), regexComment("^(;|#)(.*)$"); while(std::getline(file, szLine, '\n')) { std::smatch regexMatch; //std::string match object if(szLine == "") continue; else if(std::regex_search(szLine, regexMatch, regexComment) && regexMatch.size() > 1) m_key.push_back({"__COMMENT__", regexMatch[2], iSection}); else if(std::regex_search(szLine, regexMatch, regexSection) && regexMatch.size() > 1) { iSection = (int) m_section.size(); m_section.push_back(regexMatch[1]); } else if(std::regex_search(szLine, regexMatch, regexKey) && regexMatch.size() > 1) m_key.push_back({regexMatch.str(1), regexMatch[2], iSection}); } return; } void iniParser::write() { std::ofstream file; file.open(m_szFile, std::ios::out | std::ios::trunc); if(!file.is_open()) return; for(int j = 0; j <= m_section.size(); j++) { if(j > 0) file << "[" << m_section[j - 1] << "]\n"; for(int i = 0; i < m_key.size(); i++) { if(m_key[i].section != j - 1) continue; if(m_key[i].key == "__COMMENT__") file << ";" ; else file << m_key[i].key << "="; file << m_key[i].value << "\n"; } } return; } int iniParser::findKey(std::string szKey, std::string szSection) { for(int i = 0; i < m_key.size(); i++) if(m_key[i].key == szKey && (szSection == "" || szSection == m_section[m_key[i].section])) return i; return -1; } int iniParser::createKey(std::string szKey, std::string szSection) { int iSection = -1; if(szSection != "") { for(int i = 0; i < m_section.size(); i++) if(m_section[i] == szSection) { iSection = i; break; } } m_key.push_back({szKey, "", iSection}); return (int) m_key.size() - 1; }