Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

Don't even think twice about this, compiling C# projects is much easier than C++ ones, so you'll have no issues

...

As you are familiar with programming already, the quick and dirty setup method:

...

I come from Java and the transition was not hard. C# is mostly Java done right :P

... Have a look at the Link Compilation post and you ll find some example and tutorials near the end of the first post.

Thanks a lot for your help, guys! Turns out the "recompiling" part is pretty easy. Now I just have to get me going in the Unity/KSP API world, but I'll figure that out, I hope.

Link to comment
Share on other sites

How do I use ConfigNode.Load()?

You don't say what you are wanting to do exactly, so this is the way I use ConfigNode.Load is to save/load a file from disk to persist data.

 ConfigNode TWR1Node = ConfigNode.Load(KSPUtil.ApplicationRootPath + "GameData/Diazo/TWR1/TWR1.cfg"); //load file

and

TWR1Node.Save(KSPUtil.ApplicationRootPath + "GameData/Diazo/TWR1/TWR1.cfg"); //save the ConfigNode to disk

This requires the KSO.IO namepspace, so add "using KSP.IO;" to the start of your .cs file.

Note that in this case. TWR1.cfg can never be empty. Always add a dummy value when you create the config node because if you try to ConfigNode.Load an empty file, KSP throws a critical error and does not load it.

Here's my source code using it.

Hope that helps,

D.

Edited by Diazo
Link to comment
Share on other sites

Heyho everyone,

With 0.9 there were a lot of changes.

And one of the things that worked before was the "Click Through Prevention".

With 0.9 the old EditorLogic.fetch.lock, has become obsolete and the InputLockManager got focused.

But after fooling around with it for the night and half day. I must say, it is nolonger possible with it to prevent the release of a selected part.

I can lock a GUI.window so that it does prevents clicking at a part behind it, but I'm not able to prevent the clicking in the same window for release a selected part.

My question, is the feature just gone, or is there a Workaround, or didn't I just not find the correct methods?

Edit: noticed that the applicationlauncher in the editor has the "part release prevention" also the stating, so what is it?

Edited by Alewx
Link to comment
Share on other sites

Does anybody know the replacement for this line?

EditorPartList.Instance.categorySelected

It worked in .25 and after a 4 hours of searching for the correct method/variable, it does not seem to be possible. The goal is to enable mouse scrolling between pages and shift+mouse scrolling to change categories.

Thanks.

Link to comment
Share on other sites

Does anybody know the replacement for this line?

EditorPartList.Instance.categorySelected

It worked in .25 and after a 4 hours of searching for the correct method/variable, it does not seem to be possible. The goal is to enable mouse scrolling between pages and shift+mouse scrolling to change categories.

Thanks.

I'm looking for the same but could not find something fitting.

Quickscoll provides already the scrolling ìn the part list, but I make a similar mod.

Link to comment
Share on other sites

Does anybody know the replacement for this line?

EditorPartList.Instance.categorySelected

It worked in .25 and after a 4 hours of searching for the correct method/variable, it does not seem to be possible. The goal is to enable mouse scrolling between pages and shift+mouse scrolling to change categories.

Thanks.

The editor categories are handled in the PartCategorizer class now. I think you want to do something like this:

//Gets the "Filter by Function" category
PartCategorizer.Category filterByFunction = PartCategorizer.Instance.filters.Find(f => f.button.categoryName == "Filter by Function"), activeCategory = null;

//If the "Filter by Function" button is activated
if (filterByFunction.button.activeButton.State == RUIToggleButtonTyped.ButtonState.TRUE)
{
//Gets the category which has it's button set to true, will throw an error if theres more than one (shouldn't be happenning
activeCategory = filterByFunction.subcategories.Single(s => s.button.activeButton.State == RUIToggleButtonTyped.ButtonState.TRUE);

//You can then know the name of the category using this
string name = activeCategory.button.categoryName;
}

Basically, there is only a selected part category when it's on the Filter by Function tab. Also, some mods may add more buttons to this, like RealChute which adds a "Parachutes" category to this all, and this cannot be found in the PartCategories enum.

Link to comment
Share on other sites

The editor categories are handled in the PartCategorizer class now. I think you want to do something like this:

//Gets the "Filter by Function" category
PartCategorizer.Category filterByFunction = PartCategorizer.Instance.filters.Find(f => f.button.categoryName == "Filter by Function"), activeCategory = null;

//If the "Filter by Function" button is activated
if (filterByFunction.button.activeButton.State == RUIToggleButtonTyped.ButtonState.TRUE)
{
//Gets the category which has it's button set to true, will throw an error if theres more than one (shouldn't be happenning
activeCategory = filterByFunction.subcategories.Single(s => s.button.activeButton.State == RUIToggleButtonTyped.ButtonState.TRUE);

//You can then know the name of the category using this
string name = activeCategory.button.categoryName;
}

Basically, there is only a selected part category when it's on the Filter by Function tab. Also, some mods may add more buttons to this, like RealChute which adds a "Parachutes" category to this all, and this cannot be found in the PartCategories enum.

Thanks mate, that is already a huge help.

somehow PartCategorizer slipped through unnoticed for me.

How are your exams going,when do you await the results?

Link to comment
Share on other sites

All cleared, and I passed everything, thanks for caring :)

Cool means you will now get a degree as master of Engineering?

Found out what is used to change the category of the "Filter By Function"


PartCategorizer.SetPanel_FunctionFuelTank();

But this sets the editorLogic.mode to SIMPLE no matter it was used in ADVANCED.

Link to comment
Share on other sites

Cool means you will now get a degree as master of Engineering?

Found out what is used to change the category of the "Filter By Function"


PartCategorizer.SetPanel_FunctionFuelTank();

But this sets the editorLogic.mode to SIMPLE no matter it was used in ADVANCED.

I'm pretty sure Part<Categorizer also has a function that says "SetADVANCED()" or something, you could check to see which state it is in and force set it back to advance afterwards.

And nah for the diploma, Quebec is weird on the school system, I've been out of high school since '11, but I'm entering University in January in Physics & Computer Science :P

AvailablePart.partPath and AvailablePart.parturl are both returning null strings. Is there another way to access that information?

Apparently not. The best thing about this, is that when the PartLoader loads the part configs, it also throws out the "name" value, so you can't even lookup all the configs in GameDatabase and find the right part. Fabulous right?

Link to comment
Share on other sites

The madness only begins. Usually there are other workarounds, so if you tell us what you want to do we could help :P

It's for Filter Extensions. I want to add a "filter by mod", which to me means filtering by the folder folowing GameData. The alternative is to do it by author, but that will still need configs (which prevents me auto-generating a "Filter by Mod" category.

Link to comment
Share on other sites

It's for Filter Extensions. I want to add a "filter by mod", which to me means filtering by the folder folowing GameData. The alternative is to do it by author, but that will still need configs (which prevents me auto-generating a "Filter by Mod" category.

Well, you can still use System.IO to locate and manually load all the configs, check if they are parts, check their names, and if so mark the folder. Though that could be pretty expansive to do each time you enter the editor, so you could do it during the loading sequence of the game and store everything in a Dictionary<AvailablePart, string> where the string is the path.. Kinda sucks, but I don't believe there is an easy way to get the location of each part otherway

Link to comment
Share on other sites

Well, you can still use System.IO to locate and manually load all the configs, check if they are parts, check their names, and if so mark the folder. Though that could be pretty expansive to do each time you enter the editor, so you could do it during the loading sequence of the game and store everything in a Dictionary<AvailablePart, string> where the string is the path.. Kinda sucks, but I don't believe there is an easy way to get the location of each part otherway

Sounds about right. I already tried that, just didn't know that the name was the url so couldn't work it out :mad: (tyvm once again)

Link to comment
Share on other sites

Well, you can still use System.IO to locate and manually load all the configs, check if they are parts, check their names, and if so mark the folder.

You needn't go quite that far... The info is still there to be hunted down:

// RepairAvailablePartUrl(PartLoader.getPartInfoByName("mk1pod"));
// Log.Normal("mk1pod url: " + PartLoader.getPartInfoByName("mk1pod").partUrl);
// // mk1pod url: Squad/Parts/Command/mk1pod/mk1Pod/mk1pod
// // note: not an error; there can be multiple parts defined in a config
private void RepairAvailablePartUrl(AvailablePart ap)
{
var url = GameDatabase.Instance.GetConfigs("PART")
.FirstOrDefault(u => u.name.Replace('_', '.') == ap.name);

if (url == null)
throw new System.IO.FileNotFoundException();

// repair missing name in config if desired
if (!url.config.HasValue("name")) url.config.AddValue("name", url.name);

ap.partUrl = url.url;
}

private string GetPartPath(AvailablePart ap)
{
if (string.IsNullOrEmpty(ap.partUrl))
RepairAvailablePartUrl(ap);

var fileid = new UrlDir.UrlIdentifier(ap.partUrl);

// note: we ignore the last bit of the url because it refers to the specific entry
// in a config file. All we care about is the path to that file
return fileid.urlSplit.Take(fileid.urlDepth).Aggregate((s1, s2) => s1 + "/" + s2);
}

Edited by xEvilReeperx
Corrected bug found by Crzyrndm
Link to comment
Share on other sites

I'm pretty sure Part<Categorizer also has a function that says "SetADVANCED()" or something, you could check to see which state it is in and force set it back to advance afterwards.

And nah for the diploma, Quebec is weird on the school system, I've been out of high school since '11, but I'm entering University in January in Physics & Computer Science :P

You mean an exam to even get access to University, quite high requirements..

Setting the editormode to advanced manuall didn't work out so well in the night, maybe if I lock the Editor_Mide_Switch.

Worth another try.

Link to comment
Share on other sites

Just a really quick question gang.. Vessel.loaded, besides the obvious "Is the vessel loaded", what does that mean? What exactly does "Loaded" mean? Does its On/Off rails status affect that? What is the difference between a loaded vessel and an unloaded vessel? If I want to scan every vessel that is "on a mission" whether it is on rails or not, do I want to care about loaded status?

Link to comment
Share on other sites

As far as I can tell, if a vessel is loaded, it exists in the fully loaded state that is within the physics sphere of the currently focused vessel and it is has full physics being applied to it.

Note that this means during timewarp (not physics timewarp) when the vessel is on rails, all vessels, including the currently focused vessel, are Vessel.loaded == false.

Note I am not 100% sure about this. I know vessel goOnRails when under timewarp, I assume that also means vessel.loaded == false because that means you can't do physics operations on the vessel.

However, I've since learned about the Vessel.holdPhysics value, so I'm no longer sure if vessel.loaded still goes false when onRails.

D.

Edited by Diazo
Link to comment
Share on other sites

Ok, this is likely something stupid I'm missing, but I can't seem to get Onsave() to function. I'm trying the below code:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using UnityEngine;
using KSP;


namespace Kerbanomics
{
[KSPAddon(KSPAddon.Startup.EveryScene, false)]
public class Kerbanomics : MonoBehaviour
{
private String save_folder;
private bool billing_enabled = true;
private bool autopayEnabled = false;
private int threshold = 50;
private int level0 = 10;
private int level1 = 20;
private int level2 = 40;
private int level3 = 80;
private int level4 = 140;
private int level5 = 200;
private float standbyPct = 50;
private bool yearly = false;

private double bills = 0;
private double loanAmount = 0;
private float loanPayment = 0;
int addPay = 0;
int reqAmount = 0;
float amountFinanced = 0;
float estPayment = 0;
int payments = 10;
double pmt = 0;


private ConfigNode settings;
private ConfigNode values;


double _interval = 2300400;
public static int _lastUpdate = 0;
private Rect settingsWindow = new Rect(Screen.height / 8 + 500, Screen.width / 4 , 300, 400);
private Rect mainWindow = new Rect(Screen.width / 8 + 100, Screen.height / 4, 400, 125);
private Rect loanWindow = new Rect(Screen.width / 8 + 500, Screen.height / 4 , 400, 125);
private Rect payBills = new Rect(Screen.width / 8 + 50, Screen.height / 4, 400, 125);
public ApplicationLauncherButton button;
public static Kerbanomics Instance;


public void Awake()
{
LoadSettings();
}


public void Start()
{
if (Instance != null)
{
Destroy(Instance);
}
Instance = this;
GameEvents.onGUIApplicationLauncherReady.Add(OnGUIAppLauncherReady);
save_folder = GetRootPath() + "/saves/" + HighLogic.SaveFolder + "/";
LoadSettings();
SetInterval();
UpdateLastUpdate();
LoadData();
}


public void DestroyButtons()
{
GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIAppLauncherReady);
ApplicationLauncher.Instance.RemoveModApplication(button);
}


public override void OnSave(ConfigNode node)
{
Debug.Log("IT'S HERE, IT WORKED!");
}


void Update()
{
if (HighLogic.LoadedSceneHasPlanetarium)
{
int currentPeriod = (int)Math.Floor(Planetarium.GetUniversalTime() / _interval);
if (currentPeriod > _lastUpdate && billing_enabled == true)
{
GetInterval();
float multiplier = 106.5f;
if (yearly == true)
multiplier = 426.08f;
Debug.Log("Last Update=" + _lastUpdate + ", Current Period=" + currentPeriod);
_lastUpdate = (currentPeriod);
StringBuilder message = new StringBuilder();
message.AppendLine("Payroll is processed.");
message.AppendLine("Current staff:");
foreach (ProtoCrewMember crewMember in HighLogic.CurrentGame.CrewRoster.Crew)
{
//string crewMemberInfo = crewMember.name + " " + crewMember.rosterStatus.ToString() + crewMember.experienceLevel;
message.Append(crewMember.name);
if (!crewMember.rosterStatus.Equals(ProtoCrewMember.RosterStatus.Dead) && !crewMember.rosterStatus.Equals(ProtoCrewMember.RosterStatus.Missing))
{
float paycheck = GetWages(crewMember.experienceLevel, crewMember.rosterStatus.ToString()) * multiplier;
message.AppendLine(" is " + crewMember.rosterStatus + ". Paycheck = " + paycheck);
//Debug.Log(crewMemberInfo);
//Debug.Log("Roster Status: " + crewMember.rosterStatus.ToString());
Debug.Log("Multiplier: " + multiplier);
Debug.Log("Wages: " + GetWages(crewMember.experienceLevel, crewMember.rosterStatus.ToString()));
bills = bills + paycheck;
//Funding.Instance.AddFunds(-paycheck, 0);
}
}
Funding.Instance.AddFunds(-PayLoan(loanPayment), 0);
message.AppendLine("Thank you for your loan payment in the amount of " + loanPayment + "! Have a pleasant day!");
float externalFunding = 2500 + (247.5f * Reputation.CurrentRep);
if (yearly == true)
externalFunding = 10000 + (990 * Reputation.CurrentRep);
Funding.Instance.AddFunds(+externalFunding, 0);
message.AppendLine("Received Funding - " + externalFunding);
message.AppendLine("Amount Due: " + bills.ToString());
SaveData();
MessageSystem.Message m = new MessageSystem.Message(
"New Bill Ready",
message.ToString(),
MessageSystemButton.MessageButtonColor.RED,
MessageSystemButton.ButtonIcons.ALERT);
MessageSystem.Instance.AddMessage(m);
}
}
}
private void SetInterval()
{
if (GameSettings.KERBIN_TIME && yearly == false)
_interval = 2300400;
else if (!GameSettings.KERBIN_TIME && yearly == false)
_interval = 7884000;
else if (GameSettings.KERBIN_TIME && yearly == true)
_interval = 9201600;
else if (!GameSettings.KERBIN_TIME && yearly == true)
_interval = 31536000;
}


private double GetInterval()
{
double interval = _interval;
return interval;


}


private void UpdateLastUpdate()
{
_lastUpdate = (int)Math.Floor(Planetarium.GetUniversalTime() / GetInterval());
}


public float GetWages(int level, string status)
{
float w = level0;
switch (level)
{
case 0:
w = level0;
break;
case 1:
w = level1;
break;
case 2:
w = level2;
break;
case 3:
w = level3;
break;
case 4:
w = level4;
break;
case 5:
w = level5;
break;
default:
w = 10;
break;
}
if (status == "Available")
{
float pBuf = w / 100;
w = pBuf * standbyPct;
}
return w;
}


public void OnDestroy()
{
DestroyButtons();
}


void OnGUIAppLauncherReady()
{
this.button = ApplicationLauncher.Instance.AddModApplication(
onAppLauncherToggleOn,
onAppLauncherToggleOff,
null,
null,
null,
null,
ApplicationLauncher.AppScenes.SPACECENTER,
(Texture)GameDatabase.Instance.GetTexture("EvilCorp/Textures/icon_button_stock", false));
}

void onAppLauncherToggleOn()
{
Debug.Log("Toggled on");
RenderingManager.AddToPostDrawQueue(0, OnDraw);
Debug.Log("Saving config to" + save_folder);
Debug.Log("billing_enabled = " + billing_enabled);
Debug.Log("autopayEnabled = " + autopayEnabled);
Debug.Log("threshold = " + threshold);
Debug.Log("level0 = " + level0);
Debug.Log("level1 = " + level1);
Debug.Log("level2 = " + level2);
Debug.Log("level3 = " + level3);
Debug.Log("level4 = " + level4);
Debug.Log("level5 = " + level5);
Debug.Log("standbyPct = " + standbyPct);
Debug.Log("yearly = " + yearly);
//ResetToDefault();
}


private void OnDraw()
{
mainWindow = GUILayout.Window(854123, mainWindow, OnWindow, "Kerbanomics");
}


private void DrawSettings()
{
settingsWindow = GUILayout.Window(912361, settingsWindow, SettingsWind, "Kerbanomics Settings");
}


private void DrawLoanWindow()
{
//if (loanAmount > 0)
//{
// loanWindow = GUILayout.Window(87441, loanWindow, LoanWindLayoutDeny, "Loans");
//}
//else
//{
loanWindow = GUILayout.Window(56489, loanWindow, LoanWindLayoutApprove, "Loans");
//}
}


private double CalculateThreshold()
{
double maxPayment = 0;
float mult = threshold / 100;
maxPayment = Funding.Instance.Funds * threshold;
return maxPayment;
}


private void DrawInvoiceWindow()
{
payBills = GUILayout.Window(81365, payBills, InvoiceWindow, "Pending Bills");
}


private void OnWindow(int windowId)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Outstanding Bills: " + bills.ToString());
GUILayout.FlexibleSpace();
if (GUILayout.Button("Pay Bills"))
{
RenderingManager.AddToPostDrawQueue(0, DrawInvoiceWindow);
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Loan Balance: " + Double.Parse(loanAmount.ToString()));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Next Loan Payment: " + loanPayment.ToString());
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (GUILayout.Button("Loans", GUILayout.ExpandWidth(true)))
{
RenderingManager.AddToPostDrawQueue(0, DrawLoanWindow);
}
if(GUILayout.Button("Settings", GUILayout.ExpandWidth(true)))
{
RenderingManager.AddToPostDrawQueue(0, DrawSettings);
}
GUILayout.EndHorizontal();
GUI.DragWindow();
}


private void SettingsWind(int windowId)
{
GUILayout.BeginHorizontal();
billing_enabled = GUILayout.Toggle(billing_enabled, "Enabled");
GUILayout.FlexibleSpace();
yearly = GUILayout.Toggle(yearly, "Yearly Billing");
GUILayout.EndHorizontal();
//GUILayout.BeginHorizontal();
//GUILayout.Label("Maximum % of funds paid per period: ");
//GUILayout.FlexibleSpace();
//threshold = Convert.ToInt32(GUILayout.TextField(threshold.ToString(), 3, GUILayout.Width(50)));
//GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Level 0 Daily Wages: ");
GUILayout.FlexibleSpace();
level0 = Convert.ToInt32(GUILayout.TextField(level0.ToString(), 4, GUILayout.Width(50)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Level 1 Daily Wages: ");
GUILayout.FlexibleSpace();
level1 = Convert.ToInt32(GUILayout.TextField(level1.ToString(), 4, GUILayout.Width(50)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Level 2 Daily Wages: ");
GUILayout.FlexibleSpace();
level2 = Convert.ToInt32(GUILayout.TextField(level2.ToString(), 4, GUILayout.Width(50)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Level 3 Daily Wages: ");
GUILayout.FlexibleSpace();
level3 = Convert.ToInt32(GUILayout.TextField(level3.ToString(), 4, GUILayout.Width(50)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Level 4 Daily Wages: ");
GUILayout.FlexibleSpace();
level4 = Convert.ToInt32(GUILayout.TextField(level4.ToString(), 4, GUILayout.Width(50)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Level 5 Daily Wages: ");
GUILayout.FlexibleSpace();
level5 = Convert.ToInt32(GUILayout.TextField(level5.ToString(), 4, GUILayout.Width(50)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Percentage of Daily Wage for Standby: ");
GUILayout.FlexibleSpace();
standbyPct = Convert.ToInt32(GUILayout.TextField(standbyPct.ToString(), 4, GUILayout.Width(50)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (GUILayout.Button("Save", GUILayout.ExpandWidth(true)))
{
SaveSettings();
SetInterval();
UpdateLastUpdate();
}
if (GUILayout.Button("Reset to Default", GUILayout.ExpandWidth(true)))
{
ResetToDefault();
SaveSettings();
SetInterval();
UpdateLastUpdate();
}
if (GUILayout.Button("Close", GUILayout.ExpandWidth(true)))
{
RenderingManager.RemoveFromPostDrawQueue(0, DrawSettings);
}
GUILayout.EndHorizontal();
GUI.DragWindow();
}


private void LoanWindLayoutApprove(int windowId)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Requested Amount: ");
GUILayout.FlexibleSpace();
reqAmount = Convert.ToInt32(GUILayout.TextField(reqAmount.ToString(), 7, GUILayout.Width(75)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Interest Rate: " + CalcInterest() + "%");
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("How many payments (Max 99)? ");
GUILayout.FlexibleSpace();
payments = Convert.ToInt32(GUILayout.TextField(payments.ToString(), 2, GUILayout.Width(75)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Estimated Payment Amount: " + estPayment);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Total amount financed: " + Double.Parse(amountFinanced.ToString()));
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Calculate"))
{
float intMult = CalcInterest() / 100;
amountFinanced = reqAmount * (intMult + 1);
estPayment = amountFinanced / payments;
Debug.Log("Financed: " + amountFinanced);
Debug.Log("Estimated Payment: " + estPayment);
Debug.Log("Interest: " + intMult);
}
if (amountFinanced != 0)
{
if (GUILayout.Button("Accept"))
{
Funding.Instance.AddFunds(reqAmount, 0);
loanAmount = loanAmount + amountFinanced;
loanPayment = loanPayment + (amountFinanced / payments);
SaveData();
RenderingManager.RemoveFromPostDrawQueue(0, DrawLoanWindow);
}
}
if (GUILayout.Button("Close"))
{
RenderingManager.RemoveFromPostDrawQueue(0, DrawLoanWindow);
SaveData();
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
if (loanAmount > 0)
{


GUILayout.BeginHorizontal();
GUILayout.Label("Make a Payment: ");
GUILayout.FlexibleSpace();
addPay = Convert.ToInt32(GUILayout.TextField(addPay.ToString(), 7, GUILayout.Width(75)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Total Financed: " + loanAmount);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (GUILayout.Button("Pay", GUILayout.ExpandWidth(true)))
{
Funding.Instance.AddFunds(-addPay, 0);
PayLoan(addPay);
SaveData();
RenderingManager.RemoveFromPostDrawQueue(0, DrawLoanWindow);
}
GUILayout.EndHorizontal();
}
GUI.DragWindow();
}


private void LoanWindLayoutDeny(int windowId)
{
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("You've already borrowed money, you have to pay off your original loan before borrowing more!");
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("Additional Loan Payment: ");
addPay = Convert.ToInt32(GUILayout.TextField(loanPayment.ToString(), 7));
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if(GUILayout.Button("Pay", GUILayout.ExpandWidth(true)))
{
Funding.Instance.AddFunds(-addPay, 0);
PayLoan(addPay);
addPay = 0;
SaveData();
RenderingManager.RemoveFromPostDrawQueue(0, DrawLoanWindow);
}
if(GUILayout.Button("Close", GUILayout.ExpandWidth(true)))
{
RenderingManager.RemoveFromPostDrawQueue(0, DrawLoanWindow);
}
GUILayout.EndHorizontal();
GUI.DragWindow();
}


private void InvoiceWindow(int windowId)
{

GUILayout.BeginHorizontal();
GUILayout.Label("Amount Due: " + bills);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Payment: ");
GUILayout.FlexibleSpace();
pmt = Convert.ToDouble(GUILayout.TextField(pmt.ToString(), 7, GUILayout.Width(75)));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Pay", GUILayout.Width(75)))
{
Funding.Instance.AddFunds(-pmt, 0);
bills = bills - pmt;
SaveData();
RenderingManager.RemoveFromPostDrawQueue(0, DrawInvoiceWindow);
}
GUILayout.FlexibleSpace();
if (GUILayout.Button("Close", GUILayout.Width(75)))
{
RenderingManager.RemoveFromPostDrawQueue(0, DrawInvoiceWindow);
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUI.DragWindow();
}


void onAppLauncherToggleOff()
{
Debug.Log("Toggled off");
RenderingManager.RemoveFromPostDrawQueue(0, OnDraw);
}


public static String GetRootPath()
{
String path = KSPUtil.ApplicationRootPath;
path = path.Replace("\\", "/");
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1);
return path;
}


private void SaveSettings()
{
settings = new ConfigNode();
settings.name = "SETTINGS";
settings.AddValue("Enabled", billing_enabled);
settings.AddValue("Yearly", yearly);
settings.AddValue("Threshold", threshold);
settings.AddValue("Autopay", autopayEnabled);
settings.AddValue("WagesLevel0", level0);
settings.AddValue("WagesLevel1", level1);
settings.AddValue("WagesLevel2", level2);
settings.AddValue("WagesLevel3", level3);
settings.AddValue("WagesLevel4", level4);
settings.AddValue("WagesLevel5", level5);
settings.AddValue("StandbyPercentage", standbyPct);


settings.Save(save_folder + "Settings.cfg");
}


private void LoadSettings()
{
settings = new ConfigNode();
settings = ConfigNode.Load(save_folder + "Settings.cfg");
if (settings != null)
{
if (settings.HasValue("Enabled")) billing_enabled = Boolean.Parse(settings.GetValue("Enabled"));
if (settings.HasValue("Yearly")) yearly = Boolean.Parse(settings.GetValue("Yearly"));
if (settings.HasValue("Threshold")) threshold = (Int32)Int32.Parse(settings.GetValue("Threshold"));
if (settings.HasValue("Autopay")) autopayEnabled = Boolean.Parse(settings.GetValue("Autopay"));
if (settings.HasValue("WagesLevel0")) level0 = (Int32)Int32.Parse(settings.GetValue("WagesLevel0"));
if (settings.HasValue("WagesLevel1")) level1 = (Int32)Int32.Parse(settings.GetValue("WagesLevel1"));
if (settings.HasValue("WagesLevel2")) level2 = (Int32)Int32.Parse(settings.GetValue("WagesLevel2"));
if (settings.HasValue("WagesLevel3")) level3 = (Int32)Int32.Parse(settings.GetValue("WagesLevel3"));
if (settings.HasValue("WagesLevel4")) level4 = (Int32)Int32.Parse(settings.GetValue("WagesLevel4"));
if (settings.HasValue("WagesLevel5")) level5 = (Int32)Int32.Parse(settings.GetValue("WagesLevel5"));
if (settings.HasValue("StandbyPercentage")) standbyPct = (Int32)Int32.Parse(settings.GetValue("StandbyPercentage"));
}
}


private void SaveData()
{
values = new ConfigNode();
values.name = "VALUES";
values.AddValue("OutstandingBills", bills);
values.AddValue("LoanAmount", loanAmount);
values.AddValue("LoanPayment", loanPayment);


values.Save(save_folder + "Financials");
}


private void LoadData()
{
values = new ConfigNode();
values = ConfigNode.Load(save_folder + "Financials");
if (values != null)
{
if (values.HasValue("OutstandingBills")) bills = (Double)Double.Parse(values.GetValue("OutstandingBills"));
if (values.HasValue("LoanAmount")) loanAmount = (Double)Double.Parse(values.GetValue("LoanAmount"));
if (values.HasValue("LoanPayment")) loanPayment = (Int32)Int32.Parse(values.GetValue("LoanPayment"));
}
}


private void ResetToDefault()
{
billing_enabled = true;
autopayEnabled = false;
threshold = 50;
level0 = 10;
level1 = 20;
level2 = 40;
level3 = 80;
level4 = 140;
level5 = 200;
standbyPct = 50;
yearly = false;
}

private float PayLoan(float payment)
{
loanAmount = loanAmount - payment;
if (loanAmount == 0)
loanPayment = 0;
return payment;
}


private void TakeLoan(int loaned, int credit)
{
if (loanAmount == 0)
loanAmount = loaned * ((CalcInterest() + 100) / 100);
}


private float CalcInterest()
{
int rate = 50;
if (Reputation.CurrentRep >= 901)
rate = 5;
if ((Reputation.CurrentRep > 801) && (Reputation.CurrentRep <= 900))
rate = 10;
if ((Reputation.CurrentRep > 701) && (Reputation.CurrentRep <= 800))
rate = 15;
if ((Reputation.CurrentRep > 601) && (Reputation.CurrentRep <= 700))
rate = 20;
if ((Reputation.CurrentRep > 501) && (Reputation.CurrentRep <= 600))
rate = 25;
if ((Reputation.CurrentRep > 401) && (Reputation.CurrentRep <= 500))
rate = 30;
if ((Reputation.CurrentRep > 301) && (Reputation.CurrentRep <= 400))
rate = 35;
if ((Reputation.CurrentRep > 201) && (Reputation.CurrentRep <= 300))
rate = 40;
if ((Reputation.CurrentRep > 101) && (Reputation.CurrentRep <= 200))
rate = 45;
if ((Reputation.CurrentRep > 0) && (Reputation.CurrentRep <= 100))
rate = 50;
return rate;
}


private float CalcLoanPayment(int amount, int interest)
{
int t = interest + 100;
interest = interest / 100;
float total = amount * interest / 10;
return total;
}
}
}

When I try to compile, I get 'Kerbanomics.Kerbanomics.OnSave(ConfigNode)': no suitable method found to override' in the error log. Like I said, I'm sure it's something stupid, I've just been at this for a couple hours with no progress.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...