Fully Modifiable Custom Notifications

Sneaks

Brooklyn Bum
Joined
Oct 15, 2010
Messages
1,877
Location
NYC
Fully Modifiable Custom Notifications
Code Version 02202011.01
Authors: Sneaks, featuring much of alpaca's code.

The What:
Custom Notifications allows any mod to add custom notifications WITHOUT having to overwrite NotificationPanel.xml. This is done through a NotificationAddin and the sharing of several key values through LuaEvent functions.

Features full support for Plot Highlighting, Plot Zooming, Entering Cities on middle click, and IconHookups and CivIconHookups.
Allows for custom overrides of Vanilla notifications: You can stop them from firing or create a custom notification to override it.

The How:
1. Include the following attached 3 files to your mod:
  • NotificationPanel.lua
  • CustomNotification.lua
  • ClassUtils.lua
lib.lua has been renamed to ClassUtils.lua to deal with compatibility errors. On all 3 files, Set VFS to True.

2. Create a Notification Addin Namespace at the top of the Lua with your notification code
It will need at least 1 line:
attachment.php

Code:
include( "CustomNotification.lua" );

LuaEvents.NotificationAddin({ name = "CityGrowth", type = "CNOTIFICATION_CITY_GROWTH"})
LuaEvents.NotificationAddin({ name = "CityTile", type = "CNOTIFICATION_CULTURE_GROWTH"})
LuaEvents.NotificationOverrideAddin({ type = "NOTIFICATION_CITY_GROWTH", override = function(toolTip,summary,value1,value2) print("Overriding",toolTip,summary,value1,value2); return; end})
NOTE: When including, include the file as CustomNotification.lua rather than CustomNotification. It seems to resolve a minor bug when loading many notifications at once.
As you can see above, 2 different notifications are being added, an override is being executed, and CustomNotification is being included in the file.
For LuaEvents.NotificationAddin
The "name" field refers to the notification instance in the xml. In this case, a name of "CityGrowth" would use "CityGrowthItem" instance in the xml
The "type" field refers to the notification type. This string is determined by you, and should be unique. I would prefer if everyone used the "CNOTIFICATION_NOTIFICATIONNAME" style to keep things uniform.
For LuaEvents.NotificationOverrideAddin
The "type" field refers to the vanilla notification type you wish to override with a custom one of your own
The "override" field allows you to define a function that uses the vanilla notification's tool tip, summary, and 2 IconHookup values. This field is NOT needed if you do not need this information.
When you use the override field, the override function will execute every time the game fires the vanilla notification.

3. Create the actual Addin under the Content tab of your mod:
attachment.php

Type should be "NotificationAddin"
Name and Description are whatever you want
FileName should be the name of the file we placed the Addin code into in step 2.

4. Edit your context XML file:
attachment.php

Spoiler :
Code:
<?xml version="1.0" encoding="utf-8"?>
<Context Name="ImprovedEvents">
	<Instance Name="CityGrowthItem" >
		<Container Anchor="R,C" Size="80,80" Offset="0,0"  Hidden="0" ID="CityGrowthContainer" ConsumeMouseButton="1" >
			<SlideAnim Anchor="L,T" Style="NotificationSlide" ID="NotificationSlide" >
				<AlphaAnim Style="NewFinger" />
				<Button Anchor="R,C" Size="80,80" Offset="0,0" Texture="assets\UI\Art\Notification\NotificationFrameBase.dds" ID="CityGrowthButton"  Hidden="0" >
					<ShowOnMouseOver>
						<Image Anchor="C,C" Offset="0,0" Size="80,80" Texture="assets\UI\Art\Notification\NotificationFrameBase.dds" />
						<AlphaAnim  Anchor="C,C"  AnchorSide="O.O"  Offset="0,0" Size="80,80" Texture="assets\UI\Art\Notification\NotificationFrameGlow2.dds"  Pause="0" Cycle="Bounce" Speed="1" AlphaStart="1" AlphaEnd="0" Hidden="0"/>
					</ShowOnMouseOver>
					<Image Anchor="C,C" Offset="0,0" Size="80,80" Texture="assets\UI\Art\Notification\NotificationCityGrowth.dds" />
					<AlphaAnim Anchor="C,C" Offset="0,0" Size="80.80"  TextureOffset="0.0" Texture="assets\UI\Art\Notification\NotificationCityGrowthGlow.dds"  Pause="0" Cycle="Bounce" Speed="1" AlphaStart="0" AlphaEnd="1"/>
					<Label Anchor="C,C" Offset="0,0" String="" Font="TwCenMT20" ColorSet="Beige_Black_Alpha" FontStyle="Shadow" ID="CityGrowthCount" />
				</Button>
			</SlideAnim>
		</Container>
	</Instance>

	<Instance Name="CityTileItem" >
		<Container Anchor="R,C" Size="80,80" Offset="0,0"  Hidden="0" ID="CityTileContainer" ConsumeMouseButton="1" >
			<SlideAnim Anchor="L,T" Style="NotificationSlide" ID="NotificationSlide" >
				<AlphaAnim Style="NewFinger" />
				<Button Anchor="C,C" Size="80,80" Offset="0,0" Texture="assets\UI\Art\Notification\NotificationClearBase.dds" ID="CityTileButton"  Hidden="0" >
					<Image Anchor="C,C" Offset="0,0" Size="80,80" Texture="assets\UI\Art\Notification\NotificationTileFrame.dds" />
					<Image Anchor="C,C" Offset="0,0" Size="80,80" Texture="assets\UI\Art\Notification\NotificationTileGlass.dds" />
					<AlphaAnim Anchor="C,C" Offset="0,0" Size="80.80"  TextureOffset="0.0" Texture="assets\UI\Art\Notification\NotificationTileGlow.dds"  Pause="0" Cycle="Bounce" Speed="1" AlphaStart="0" AlphaEnd="1"/>
					<Label Anchor="C,C" Offset="0,0" String="" Font="TwCenMT20" ColorSet="Beige_Black_Alpha" FontStyle="Shadow" ID="CityTileCount" />
				</Button>
			</SlideAnim>
		</Container>
	</Instance>
</Context>
This is an image/code of my ImprovedEvents.xml file. It is absolutely important that this XML has the SAME name as the .lua file that runs the event. So, if I am running a RandomEvents.lua, the random events notifications should be in RandomEvents.xml.

Now, notice a few things about the code above: the Context field has been given Name="ImprovedEvents". Make sure to add a 'Name = "ContextName" ' to your XML as well. It should be the same as the actual XML name. So, for a RandomEvents.xml, the line should read: <Context Name="RandomEvents">

If you are using Images that require an IconHookup or CivIconHookup, read carefully. The supported naming conventions are as follows:
-All IconHookup images should begin with either "Resource", "Building", "Wonder", "Project", "Civ", "Unit", "Tech", "Natural", "Specialist", "Policy", "Promotion", "Leader", or "Custom".
So, if my notification features 2 Civilization images, I would name them "Civ1" and "Civ2". Additional pieces for Civ icons should follow this pattern (i.e. Civ1IconBG, Civ1IconShadow).
Special Note: When adding Leader images, use the value for the Leader's Civilization, rather than the leader itself.

5. Adding the Notification to your Lua.
Next, the notification function itself:
Code:
CustomNotification(Name, Summary, ToolTip, Plot, City, Highlight, Table)

Lets go through these variables one at a time:
Name - String value: Refers to the name of the notification in the XML.
Summary - String value: The text that appears to the left of the notification icon as it appears.
ToolTip - String value: The text that appears when you mouse over the notification icon.
Plot - Variable: This is the plot that the game will center in on if the notification is clicked. Enter 0 if you do not want your notification to have this feature. If set to 0, but a City value exists, it will automatically assign the city's plot to this variable.
City - Variable: The city screen of this city will appear if the notification is middle clicked. Enter 0 if you do not want your notification to have this feature.
Highlight - Variable: This is the color the Plot will be highlighted with. This will look similar to the next plot acquisition highlights in the city screen. Acceptable inputs are Vector4 codes, "Blue", "White", "Black", "Yellow", "Green", "Red", "Magenta", "Cyan". Enter 0 if you do not want your notification to have this feature.
Table - Table name: This is where you will include a table if your notification requires IconHookups. This will be explained more below. Enter 0 if you do not need this feature.

An Example:
Code:
CustomNotification("CityTile", Locale.ConvertTextKey("TXT_KEY_NOTIFICATION_SUMMARY_CITY_TILE", pCity:GetName()), Locale.ConvertTextKey("TXT_KEY_NOTIFICATION_CITY_TILE", pCity:GetName()), pPlot, pCity, "Magenta", 0)
In this case, the game will run the custom "CityTile" notification. The summary and tooltip are being grabbed from text keys. pPlot and pCity are both given, so this notification will allow centering on pPlot, and will open up pCity on middle click. The notification will also highlight pPlot in magenta. Because this notification does not need to hookup any icons, the table value is 0.

Tables in detail:
To add a table, create the a table for your notification right before you add the CustomNotification() function. The table should look like this:
Code:
TableName = {{IDNeedingHookup, Value, Icon Size, Has Met Check, Custom},{IDNeedingHookup2, Value2, Icon Size2, Has Met Check2, Custom2}}

IDNeedingHookup - The ID string in the XML that needs an icon hookup
Value - The value of the item we are hooking up.
Icon Size - The size of the icon. An entry of 0 will default to the basic size of 80 for most Icons, and 64 for those without size 80 atlases.
Has Met Check - Boolean true/false. Only applies to Civilization, Leader, and Policy icon hookups.
For Civ and Leaders: If True, the game will check to see if the player has met that civ before displaying the image. An entry of 0 will default to false.
For Policies: If True, the game will use the "Achieved" icon for the policy (gold rather than silver). An entry of 0 will default to false.
Custom - If you need to hookup an icon from a custom table, define the table here. The table should have PortraitIndex and IconAtlas values in its rows. An entry of 0 can be used if not needed.

Heres an example:
Code:
MyNotificationTable = {{"Civ1", Player1ID, 45, true, 0},{"Resource1",resourcechosen,0,0,0}}
In this case, we are hooking up a Civilization Icon and a Resource Icon. The Civilization icon has an ID of "Civ1" in the XML. The value of Player1ID is the ID of the Civ we want to display. The image size will be 45, and true means the game will check to see if we have met the Civ in question before displaying their picture. If we have not, it will default to a '?' image. The Resource has an ID of "Resource1" in the xml. resourcechosen has the value of the resource. Since the next 2 values are 0, the size will default to 80, and HasMet check to false.

Any questions, please ask.
 

Attachments

  • customnoti3.gif
    customnoti3.gif
    57.2 KB · Views: 2,626
  • CustomNotifications.zip
    CustomNotifications.zip
    9.4 KB · Views: 193
  • CustomNotiV2-1.gif
    CustomNotiV2-1.gif
    21.3 KB · Views: 2,292
  • CustomNotiV2-2.gif
    CustomNotiV2-2.gif
    16.1 KB · Views: 2,310
Nice work Sneaks. I'll try it out soon and likely use it in a Building Resources update. In the mean time, I've linked this to my CustomNotifications OP. :thumbsup:
 
Great work :goodjob:

It seems that it still modifies the vanilla NotificationPanel.lua, doesn't it? Would be cool if you could modify your solution in a way that it won't change this file anymore - maximum independence :) (the solution i posted in Whys' thread does not modify any vanilla files)
 
Excellent tutorial, thank you for the detailed walkthrough. It really helps to have the person who wrote code explain how it works. :D

I seem to be adding the file to the project incorrectly. Do you spot what's wrong with this? I'm getting an "error loading file" like it doesn't exist.
 

Attachments

  • Notifications.JPG
    Notifications.JPG
    301.2 KB · Views: 142
Hmm, seems ok. Cannot tell just from that. Mind sending me the project so I can tinker?

ACTUALLY, as I recall, looking at your files, you do not have lib.lua set to VFS true, and instead are UIAddin inserting it. Take out the UIAddin, and set it to true.
 
Great work :goodjob:

It seems that it still modifies the vanilla NotificationPanel.lua, doesn't it? Would be cool if you could modify your solution in a way that it won't change this file anymore - maximum independence :) (the solution i posted in Whys' thread does not modify any vanilla files)

True, but this provides 'Addin' functionality, similar to alpaca's 'DiploCornerAddin'. Admittedly, I haven't looked at the pros and cons in detail as yet.
 
Adding the NotificationPanel does make this a bit less Mod-friendly, but I decided it was worth it for several reasons:

1. This system adds a massive amount of customizable options in a relatively user-friendly package.
2. I have added hooks for a NotificationOptions addin which will allow for a DiploCorner menu that can customize exactly what popups will show for vanilla and mods. I already have a working version of this based on alpaca's which I will upload shortly.
 
Sweeeeeet. I probably won't have enough time to start in on this for RCS tonight, sadly. I just caught myself starting to ask whether it'd be better to import these files directly into my mod or to just create a dependency... and when I realized what I was saying, I became sad. Oh well.
 
Here's the project folder. I have the feeling I'm missing something really obvious you probably already pointed out in the tutorial. :lol:

Lately I've been bogged down in details of implementation and tend to overlook more general things...

Lib.lua is imported to the VFS, I tried removing it from InGameUIAddin to no effect. From what I've seen it doesn't seem to matter if a mod is imported through InGameUIAddin or not if it's already got the VFS import flag set, so I tend to leave things there even after I've changed how they're loaded.
 
Found a few issues:

Any Context xml files need to be set VFS to true because they are not Gameplay files.

Second, the file naming schema is this:

ModName.lua - the file that has the CustomNotification events in it
ModName.xml - the file with the notification contexts
ModNameAddin.lua - the Notification Addin. Name doesn't matter in the least.

In your case, the Addin has the same name as the context file, instead of the actual Lua event file having the same name.

So, a solution would be this:

Rename BC - General.lua to BC - Events.lua (or something like that)
Rename BC_Notifications.xml to BC - Events.xml

Set VFS to true on both files.

Give it a spin, and let me know how it goes.
 
Ahh... just as I suspected, an obvious thing you pointed out! :D

If in the future I wanted to create a library of custom notifications to use in multiple files, is there a way to do so? Would it work to create a function in the library to display the custom notification that's then called by outside files, or would the contexts not work that way? I really don't know much about using contexts.
 
Should work so long as the final file creating the notification has all the XML contexts.
 
I have a request. I'd like to override handling of one of the default game notifications (city starvation), but the function calling that notification is on the c++ side of things.

Would it be difficult to code in the capability for addins to this system to register intercepts for notifications, and generate an event for these mods to run a custom procedure, somewhere around line 152 of your version of NotficiationPanel.lua?
 
Should be able to do it. I wanted to add in Icon capacity for Citizen icons anyhow, so I'll attempt adding that at the same time.
 
Thanks!

This'll be really helpful for the maritime thing I'm doing. Seek pointed out a city with negative surplus food from normal sources, and the modded MCS addition bringing it up into the green, gives starvation warnings even though it's growing. :crazyeye:
 
My plan is this.
I'll add an override function that will run a function you specify in the NotificationAddin file.

So, it'll look like this for you
Code:
LuaEvents.NotificationOverrides( {type=NOTIFICATION_STARVING, override=function(tooltip,summary,value1,value2) LuaEvents.CustomStarving(); end};)

The tooltip,summary,value1,value2 will be the values that come automatically with the vanilla notification if you want to reuse them.
 
Try out the attached Notification Panel. I have not tested it myself, so give it a whirl, and get me some feedback
 

Attachments

Some emergencies came up in personal life... my father fell on some ice and broke his arm rather badly. :undecide: I've been in the hospital lately taking care of him.

He's recovering well now and back home again, so I've got time to sit down and work out this notification thing. :goodjob:
 
Back
Top Bottom