Skip to content

Commit

Permalink
Added and cleaned up documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
rob-williams committed Oct 31, 2015
1 parent f974f11 commit a059a13
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 34 deletions.
8 changes: 4 additions & 4 deletions CityVitalsWatchLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class CityVitalsWatchLoader : ILoadingExtension {
private static CityVitalsWatchPanel Panel = null;

/// <summary>
/// Creates the City Vitals Watch panel.
/// Loads the mod's settings and creates the City Vitals Watch panel.
/// </summary>
public static void CreatePanel() {
CityVitalsWatch.Settings = CityVitalsWatchSerializer.LoadSettings();
Expand All @@ -34,7 +34,7 @@ public static void CreatePanel() {
}

/// <summary>
/// Destroys the City Vitals Watch panel.
/// Saves the mod controls' positions to settings and destroys the City Vitals Watch panel.
/// </summary>
public static void DestroyPanel() {
var resolutionData = CityVitalsWatch.Settings.GetResolutionData(Screen.currentResolution.width, Screen.currentResolution.height);
Expand Down Expand Up @@ -78,9 +78,9 @@ public void OnLevelUnloading() {
}

/// <summary>
/// Called when the mod is released. Does nothing.
/// Called when the mod is released; does nothing.
/// </summary>
public void OnReleased() {
}
}
}
}
68 changes: 47 additions & 21 deletions CityVitalsWatchPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public UIButton ToggleButton {
/// Called before the first frame after the panel is created.
/// </summary>
public override void Start() {
// Find the top-level UIView object containing all game controls to copy
foreach (var uiView in GameObject.FindObjectsOfType<UIView>()) {
if (uiView.name == "UIView") {
this.uiParent = uiView;
Expand Down Expand Up @@ -79,7 +80,7 @@ public override void Start() {
// If for some reason control setup threw an exception, destroy the panel instead of staying broken
GameObject.Destroy(this.gameObject);

// Rethrow the exception to help debug any issues
// Rethrow the exception to help debug any issues (Message is not helpful, but StackTrace is)
throw new Exception(e.Message + " - " + e.StackTrace);
}
}
Expand Down Expand Up @@ -135,6 +136,7 @@ private void SetUpControls() {
// Grab a label from the electricity panel to use as a template for the settings panel label
UILabel labelTemplate = electricityPanel.Find<UILabel>("ElectricityAvailability");

// Create and position all non-stat controls first
this.CreatePanelTitle(titleFont);
this.CreateDragHandle();
this.CreatePanelButtons();
Expand All @@ -149,6 +151,7 @@ private void SetUpControls() {
negativeColor = Singleton<InfoManager>.instance.m_properties.m_modeProperties[4].m_negativeColor;
}

// zOrder must be manually assigned so the controls are aligned properly by the UI framework
int zOrder = 1;

// Set up electricity controls
Expand Down Expand Up @@ -431,43 +434,62 @@ private void CreateSettingsPanel(UIFont titleFont, UILabel labelTemplate) {
/// <summary>
/// Creates a new label and copies the properties of the provided template.
/// </summary>
/// <param name="templateLabel">The label template.</param>
/// <param name="labelTemplate">The label template.</param>
/// <returns>The created label.</returns>
private UILabel CreateLabel(UILabel templateLabel) {
GameObject labelObject = new GameObject(templateLabel.name);
private UILabel CreateLabel(UILabel labelTemplate) {
GameObject labelObject = new GameObject(labelTemplate.name);
labelObject.transform.parent = this.infoPanel.transform;
UILabel label = labelObject.AddComponent<UILabel>();
label.font = templateLabel.font;
label.textColor = templateLabel.textColor;
label.textScale = templateLabel.textScale;
label.localeID = templateLabel.localeID;
label.font = labelTemplate.font;
label.textColor = labelTemplate.textColor;
label.textScale = labelTemplate.textScale;
label.localeID = labelTemplate.localeID;
return label;
}

/// <summary>
/// Creates a new availability meter using the standard meter sprite.
/// </summary>
/// <param name="statName">The name of the meter's stat, used for object naming.</param>
/// <returns>The created availability meter.</returns>
private UISlider CreateAvailabilityMeter(string statName) {
// Create the slider
GameObject sliderObject = new GameObject(statName + "Meter");
sliderObject.transform.parent = this.infoPanel.transform;
UISlider slider = sliderObject.AddComponent<UISlider>();
slider.width = MeterWidth;
slider.height = MeterHeight;
slider.backgroundSprite = "MeterBackground";

// Create the indicator
GameObject indicatorObject = new GameObject(statName + "Indicator");
indicatorObject.transform.parent = slider.transform;
UISprite indicator = indicatorObject.AddComponent<UISprite>();
indicator.spriteName = "MeterIndicator";
indicator.width = MeterIndicatorSize;
indicator.height = MeterIndicatorSize;
slider.thumbObject = indicator;

return slider;
}

/// <summary>
/// Creates a new gradient meter using the specified meter texture and colors.
/// </summary>
/// <param name="statName">The name of the meter's stat, used for object naming.</param>
/// <param name="gradientTexture">The texture to used for the meter's gradient.</param>
/// <param name="colorA">The color to render on the left side of the meter.</param>
/// <param name="colorB">The color to render on the right side of the meter.</param>
/// <returns>The created gradient meter.</returns>
private UISlider CreateGradientMeter(string statName, UITextureSprite gradientTexture, Color colorA, Color colorB) {
// Create the slider
GameObject sliderObject = new GameObject(statName + "Meter");
sliderObject.transform.parent = this.infoPanel.transform;
UISlider slider = sliderObject.AddComponent<UISlider>();
slider.width = MeterWidth;
slider.height = MeterHeight;

// Create the indicator
GameObject indicatorObject = new GameObject(statName + "Indicator");
indicatorObject.transform.parent = slider.transform;
UISprite indicator = indicatorObject.AddComponent<UISprite>();
Expand All @@ -476,6 +498,7 @@ private UISlider CreateGradientMeter(string statName, UITextureSprite gradientTe
indicator.height = MeterIndicatorSize;
slider.thumbObject = indicator;

// Create the gradient texture and setup how its material is rendered
UITextureSprite gradient = GameObject.Instantiate<UITextureSprite>(gradientTexture);
gradient.name = statName + "Gradient";
gradient.transform.parent = slider.transform;
Expand Down Expand Up @@ -602,6 +625,7 @@ private void UpdateDisplay() {
int universityNeed = 0;
float unemployment = 0f;

// Grab all of the stat values from the singleton DistrictManager instance
if (Singleton<DistrictManager>.exists) {
var info = Singleton<DistrictManager>.instance.m_districts.m_buffer[0];
electricityCapacity = info.GetElectricityCapacity();
Expand Down Expand Up @@ -634,22 +658,23 @@ private void UpdateDisplay() {
unemployment = info.GetUnemployment();
}

// Fire hazard is stored in the singleton ImmaterialResourceManager instead
if (Singleton<ImmaterialResourceManager>.exists) {
Singleton<ImmaterialResourceManager>.instance.CheckTotalResource(ImmaterialResourceManager.Resource.FireHazard, out fireHazard);
}

if (this.electricityMeter != null) {
this.electricityMeter.value = this.GetPercentage(electricityCapacity, electricityConsumption);
this.electricityMeter.value = this.GetAvailabilityPercentage(electricityCapacity, electricityConsumption);
this.electricityMeter.tooltip = this.GetUsageString(electricityCapacity / 1000f, electricityConsumption / 1000f);
}

if (this.waterMeter != null) {
this.waterMeter.value = this.GetPercentage(waterCapacity, waterConsumption);
this.waterMeter.value = this.GetAvailabilityPercentage(waterCapacity, waterConsumption);
this.waterMeter.tooltip = this.GetUsageString(waterCapacity, waterConsumption);
}

if (this.sewageMeter != null) {
this.sewageMeter.value = this.GetPercentage(sewageCapacity, sewageAccumulation);
this.sewageMeter.value = this.GetAvailabilityPercentage(sewageCapacity, sewageAccumulation);
this.sewageMeter.tooltip = this.GetUsageString(sewageCapacity, sewageAccumulation);
}

Expand All @@ -665,12 +690,12 @@ private void UpdateDisplay() {
}

if (this.incineratorMeter != null) {
this.incineratorMeter.value = this.GetPercentage(incinerationCapacity, garbageAccumulation);
this.incineratorMeter.value = this.GetAvailabilityPercentage(incinerationCapacity, garbageAccumulation);
this.incineratorMeter.tooltip = this.GetUsageString(incinerationCapacity, garbageAccumulation);
}

if (this.healthcareMeter != null) {
this.healthcareMeter.value = this.GetPercentage(healCapacity, sickCount);
this.healthcareMeter.value = this.GetAvailabilityPercentage(healCapacity, sickCount);
this.healthcareMeter.tooltip = this.GetUsageString(healCapacity, sickCount);
}

Expand All @@ -691,7 +716,7 @@ private void UpdateDisplay() {
}

if (this.crematoriumMeter != null) {
this.crematoriumMeter.value = this.GetPercentage(cremateCapacity, deadCount);
this.crematoriumMeter.value = this.GetAvailabilityPercentage(cremateCapacity, deadCount);
this.crematoriumMeter.tooltip = this.GetUsageString(cremateCapacity, deadCount);
}

Expand All @@ -706,22 +731,22 @@ private void UpdateDisplay() {
}

if (this.jailMeter != null) {
this.jailMeter.value = this.GetPercentage(criminalCapacity, criminalAmount + extraCriminalAmount);
this.jailMeter.value = this.GetAvailabilityPercentage(criminalCapacity, criminalAmount + extraCriminalAmount);
this.jailMeter.tooltip = this.GetUsageString(criminalCapacity, criminalAmount + extraCriminalAmount);
}

if (this.elementarySchoolMeter != null) {
this.elementarySchoolMeter.value = this.GetPercentage(elementarySchoolCapacity, elementarySchoolNeed);
this.elementarySchoolMeter.value = this.GetAvailabilityPercentage(elementarySchoolCapacity, elementarySchoolNeed);
this.elementarySchoolMeter.tooltip = this.GetUsageString(elementarySchoolCapacity, elementarySchoolNeed);
}

if (this.highSchoolMeter != null) {
this.highSchoolMeter.value = this.GetPercentage(highSchoolCapacity, highSchoolNeed);
this.highSchoolMeter.value = this.GetAvailabilityPercentage(highSchoolCapacity, highSchoolNeed);
this.highSchoolMeter.tooltip = this.GetUsageString(highSchoolCapacity, highSchoolNeed);
}

if (this.universityMeter != null) {
this.universityMeter.value = this.GetPercentage(universityCapacity, universityNeed);
this.universityMeter.value = this.GetAvailabilityPercentage(universityCapacity, universityNeed);
this.universityMeter.tooltip = this.GetUsageString(universityCapacity, universityNeed);
}

Expand All @@ -732,12 +757,13 @@ private void UpdateDisplay() {
}

/// <summary>
/// Calculates a percentage based on the specified capacity and consumption values using Cities: Skylines' percentage algorithm.
/// Calculates an availability percentage based on the specified capacity and consumption values using
/// Cities: Skylines' percentage algorithm.
/// </summary>
/// <param name="capacity">The capacity value.</param>
/// <param name="consumption">The consumption value.</param>
/// <returns>The percentage.</returns>
private float GetPercentage(int capacity, int consumption, int consumptionMin = 45, int consumptionMax = 55) {
/// <returns>The availability percentage.</returns>
private float GetAvailabilityPercentage(int capacity, int consumption, int consumptionMin = 45, int consumptionMax = 55) {
/* This algorithm is what's used by the class InfoViewPanel to determine percentages displayed through the UI.
* I'm unaware of the reasons for choosing the default values for consumptionMin and consumptionMax, but I
* wanted to keep the logic consistent with the built-in UI sliders (obviously basePercent is always
Expand Down
6 changes: 3 additions & 3 deletions CityVitalsWatchResolution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
public class CityVitalsWatchResolution {

/// <summary>
/// The width of the screen.
/// The width of the screen at this resolution.
/// </summary>
public int ScreenWidth;

/// <summary>
/// The height of the screen.
/// The height of the screen at this resolution.
/// </summary>
public int ScreenHeight;

Expand All @@ -35,4 +35,4 @@ public class CityVitalsWatchResolution {
/// </summary>
public float ToggleButtonPositionY = 12f;
}
}
}
2 changes: 1 addition & 1 deletion CityVitalsWatchSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ public static void SaveSettings(CityVitalsWatchSettings settings) {
}
}
}
}
}
3 changes: 2 additions & 1 deletion CityVitalsWatchSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public CityVitalsWatchResolution GetResolutionData(int screenWidth, int screenHe
}
}

// If no resolution data was found, create new default data for the specified resolution
if (resolutionData == null) {
resolutionData = new CityVitalsWatchResolution();
resolutionData.ScreenWidth = screenWidth;
Expand Down Expand Up @@ -232,4 +233,4 @@ public void SetStatDisplayed(CityVitalsWatchStat stat, bool value) {
}
}
}
}
}
13 changes: 10 additions & 3 deletions CityVitalsWatchSettingsPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
/// </summary>
public class CityVitalsWatchSettingsPanel : UIPanel {

/// <summary>
/// Maps a <see cref="CityVitalsWatchStat"/> to the localization ID of the label used for its name.
/// </summary>
private static readonly Dictionary<CityVitalsWatchStat, string> StatLocaleIdMap = new Dictionary<CityVitalsWatchStat, string>
{
{ CityVitalsWatchStat.ElectricityAvailability, "INFO_ELECTRICITY_AVAILABILITY" },
Expand Down Expand Up @@ -146,13 +149,15 @@ private void CreateControlPanel() {
/// <param name="zOrder">The order index of the control used when automatically layout out the control.</param>
/// <returns>The created check box control.</returns>
private UICheckBox CreateSettingsControl(bool value, string localeId, bool setRawText, UILabel labelTemplate, ref int zOrder) {
// First, create the check box for the setting
GameObject checkBoxObject = new GameObject("CheckBox" + zOrder);
checkBoxObject.transform.parent = this.controlPanel.transform;
UICheckBox checkBox = checkBoxObject.AddComponent<UICheckBox>();
checkBox.autoSize = true;
checkBox.zOrder = zOrder;
zOrder++;


// Create the sprite displayed when the check box is unchecked and position it within the check box
GameObject uncheckedObject = new GameObject("Unchecked");
uncheckedObject.transform.parent = checkBox.transform;
UISprite uncheckedSprite = uncheckedObject.AddComponent<UISprite>();
Expand All @@ -161,6 +166,7 @@ private UICheckBox CreateSettingsControl(bool value, string localeId, bool setRa
uncheckedSprite.height = 16f;
uncheckedSprite.relativePosition = new Vector3(3f, 3f);

// Create the sprite displayed when the check box is checked and position it within the check box
GameObject checkedObject = new GameObject("Checked");
checkedObject.transform.parent = uncheckedSprite.transform;
UISprite checkedSprite = checkedObject.AddComponent<UISprite>();
Expand All @@ -170,6 +176,7 @@ private UICheckBox CreateSettingsControl(bool value, string localeId, bool setRa
checkedSprite.relativePosition = Vector3.zero;
checkBox.checkedBoxObject = checkedSprite;

// Create the label to display the setting's name and position it within the check box
GameObject labelObject = new GameObject("Label");
labelObject.transform.parent = checkBox.transform;
labelObject.transform.localPosition = Vector3.zero;
Expand Down Expand Up @@ -223,11 +230,11 @@ private void OnCloseButtonClick(UIComponent component, UIMouseEventParameter eve

this.isVisible = false;

// If any settings were changed, re-create the panel
// If any settings were changed, recreate the panel
if (settingsChanged) {
CityVitalsWatchLoader.DestroyPanel();
CityVitalsWatchLoader.CreatePanel();
}
}
}
}
}
2 changes: 1 addition & 1 deletion CityVitalsWatchStat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ public enum CityVitalsWatchStat {
UniversityAvailability,
Employment,
}
}
}

0 comments on commit a059a13

Please sign in to comment.