Entries in doing and learning (8)

Sunday
Jun202010

Digital Generations - Why They Have an Impact Now and in the Future

Just the other day I had some wonderful discussions with several long time colleagues and friends at a social event. Invariably we wandered into the realm of what we observed in the marketplace and what we believed it meant.

One of the major topics we discussed happened to be what we called the digital generations. These are generations that have significant exposure to the likes of the Internet in their lives which sets them apart from earlier generations.

One of the key differences we noticed was that the current and future digital generations are looking to extend what would be the classic human network not only into the real world but the digital world. This desire is not really surprising. However the degree of impact it has on individuals is very significant. I am not simply talking about what many would consider isoteric discussions but rather a very pragmatic and practical shift between generations. For example it is not uncommon for both generations to reach out to their network of contacts to ask questions. What is fundamentally different between the two is the degree of reach, immediacy and value. Earlier generations tend to reach out via email or phone after they have debated on whether to ask the question. This means they obtain feedback in what can be hours to days. However, using more immediate mediums such as Twitter or Facebook, those of the digital age get answers within minutes to hours. This means that they can make decisions more quickly and potentially with better quality since they can reach more people more quickly. This ability to "crowdsource" answers is a powerful extension for young professionals. It enables them to navigate through issues at a far faster pace than prior generations using mediums that while technically not out of reach from older generations, philosophically are unattainable due to the widely different attitudes. This appears to a business that younger or more digitally adept professionals are able to move more quickly and decisively with what appears to be less information than others which is a must to maintain competitive advantages in highly pressured markets.

Another intriguing point that I and many of my colleagues have noticed as well is the fundamental difference in learning between digitally adept individuals and prior generations. Whether it be crowdsourcing with their social networks, sharing and collaborating using technologies such as Google or BoxNet, catching up to news via Twitter, learning new things via YouTube, Vimeo, and podcasts, the digitally adept share a common ability to absorb, navigate and filter multiple streams of information and derive value that is interesting to them. The fundamental behaviors that I see are reflections of common requirements in a professional world: problem solving, information seeking, education synthesis, learning, and practical application of knowledge. They are learning these skills in addition to their traditional education by performing them intuitively to meet their needs in a digital world. A very simple and specific use case would be wireless networking. This is a task that most older professionals explore very rarely; most will be happy with a wireline cable connection. Yet wireless is a more common task especially with regard to gaming consoles for the digitally adept. They search the web for answers to questions that they have, troubleshoot problems and finally achieve the end result they were looking for which is to play games or watch movies wirelessly. The end result is that someone who is perhaps younger or digitally adept is actually much more experienced with technical issues that many older individuals find daunting and quite foreign. This learning follows them in the industry where they are capable of learning concepts much more quickly since they have a very strong base of understanding with which to grow from which may not always be the case for their experienced counterparts.

The differences we noticed between the generations is how comfortable the digitally connected generations are to technology. They do not see it as something bizarre or foreign. Rather something that is a part of their life. This fundamentally different view of the digital world gives them insights that prior generations are simply lacking. These insights make them more comfortable in the industry where technology for many companies is still viewed with suspicion and fear. More importantly by moving past these prejudices they are able to come to solutions more quickly, with greater confidence and in many cases with better perspectives of what really matters to people.

Tuesday
Mar092010

Why Companies Lay People Off - Preparing for that Possibility

Through my long career losing one's job is a very traumatic experience to anyone the first time around. It actually gets easier subsequent times since much of the initial shock and pain found in the first layoff has taught a professional how to be better prepared for it.

In the recent economic turmoil many more professionals have found themselves on different paths than what they thought they would experience. For many it is their first time or so long since they have gone through the experience that their pain, confusion and angst is understandably high. Even the most seasoned professional looks at the situation with some degree of frustration and confusion. After all they were doing fairly important work and now suddenly they are out of an organization they have given so much of their efforts to.

I often find myself giving advice to many professionals in these situations from my own personal perspective in that I have gone through it myself several times. Many have found my advice useful so I thought I would share some of my thoughts on the subject:

  • Why is a company laying off? Answer - economic reality bites. Let's face it, many companies are not necessarily well prepared for change especially rapid, downward changes. So when they do take actions, it is often more of a reaction than any truly planned action. This is not to say that any organization releases employees lightly. Quite to the contrary they are loathe to do so. However it is not something that they adequately prepare for nor practice until times call for it. Quite simply it is beyond an organization's control on when they lay people off. It just happens.
  • So why am I being laid off? Answer - it's nothing personal, it's just business. Most companies view their employees as valuable resources not necessarily as individuals. Even in the most individual-oriented company, everyone has a value that has to be weighed by the company process in terms of being retained or released. For example younger more agile individuals even those who have contributed significantly to a company can find themselves released while others are retained. Why? The company weighs their value to the company. If a person only contributes in a certain way that can be more or less valuable to a company versus others who do more. To be honest there is no real "formula" or "scientific process" being applied. It is matter of perception by decision makers beyond an individuals control.
  • Was it something that "I" did to get laid off? Answer - Plain and simply no. In almost all instances of being laid off I can personally recall every "mishap" that might have caused my being released. From personal experience that is the wrong avenue to take. While it is true that one might have made mistakes, if they had been heinous enough to cause a layoff more than likely one would have been released due to disciplinary actions prior to being laid off. One of the biggest wastes of energy is looking at a company and imagining any number of scenarios as to why one was laid off. It ranges from "so-and-so was out to get me", "I should have explained my value more", "I should have done more tasks", etc. I have seen executives of profitable divisions who did outstanding work, engineers with PhDs and patents, and sales personnel who brought large deals to an organization released in the same wave as other professionals who were not as well known. It is never one's fault for being affected by a layoff in such dire economic times. 
  • What do I do now? Answer - Simple. Find a new opportunity. Note how I always call it an opportunity and not a job? This is an important distinction. An opportunity is something that interests you whereas a job is something that does not. It is the passion driven by interest that attracts employers. If you are interested in doing something it shows.

One of the major perspectives someone being laid off tends to forget is how their departure among the number of their fellow employees impacts their organization. I am not merely talking about immediate work efforts but rather morale as a whole. How an organization deals with a layoff is not only important to those leaving, but those staying as well. While it is true that many employees will react out of fear of losing their positions, energy that is fear-based lasts only a short while. Employees will become resentful, fearful and stressed resulting in any number of issues to an organization ranging from late projects, to health-related absences, to a poisoning of the company culture - just to name a few. Essentially when a lay off occurs, it erodes the goodwill between employee and employer. How well the transition is managed determines how much erosion occurs and how soon the healing process begins. I often advise those who are let go that their worries are over and their course of action is clear. Those that remain behind are the ones that need sympathy and support as their turmoil will take a long time to settle down.

One of the greatest lessons being laid off teaches a professional is how to be entrepreneurial - to find opportunities, to network, to grow, to find business own their own, to face repeated rejection with optimism and enthusiasm, and to ultimately believe in themselves. As companies continue to lower their costs by letting employees go, they are in my opinion inadvertantly creating a newer, better workfoce that will have several traits:

  • More self-reliant and self-motivated.
  • More focused on doing what they themselves are capable of doing for others both inside and outside of an organization.
  • More confidant in their capabilities and values in delivering quality, affordable and effective solutions to customers.
  • More capable of making significant decisions that affect their lives with greater clarity and determination than before.
  • More unwilling to "settle" for something as opposed to going out and "making" it happen.

These are not bad traits to have in any employee. It is just that employers will find a more mindful, independent workforce than they previously thought. This workforce will not only have the talent but the the motivation to focus on what interests them. For any professional going through a transition focus on the future, not the past. Trust me, it helps.

 

Thursday
Jan212010

Keeping Up To Date - How To Adjust to Challenging Times

I read an article today from The Economist entitled "The Trap: The Curse of Long-Term Unemployment Will Bedevil the Economy". There are some very true and fascinating comments in this article which have been stated over and over again by other experts.

In today's workplace there are many observations about the changing landscape such as this one from Vocii which demonstrates how some CEOs are adjusting to the times. Yet for many professionals these concepts used by executives are elusive. One of the core principles I have attempted to pass along to other colleagues has been the concept of keeping current and competitive with ones skills. This is what CEOs and executives do, this is what all working professionals should do. This is especially true of technical professionals.

Technology changes rapidly creating a great number of challenges and opportunities at the same time. It creates more of a level playing field though it has it's extremes. Often times I come across numerous technical professionals that spend all their time working job searches and resume changes, yet totally ignoring the fact that their skills may in fact need ot be honed as well. Admittedly looking for the next opportunity is very important as is having a very good resume demonstrating your value. However, in the end you need to possess the skills that organizations want. Most have very good skills but need some refinement. Others need to learn whole new skill sets.

In my experience keeping abreast of technology is part of a technical professionals career. Admittedly indepth knowledge on the detailed technology may not be as pressing depending on your exact role, but one cannot be even a CTO or CIO without some passing knowledge of the latest approaches. I run into many technical professionals with very deep knowledge in a few skills or such a broad aptitude with little capability of applying modern solutions to significant problems.

I often use my own approach in keeping skills current as a means to inspire others. I mentor several startups in their business models and technical executions. I also mentor numerous working professionals by helping them deliver innovative solutions into their areas of responsibility which allows them to gain new skills while leveraging existing knowledge areas. I also help many technical implementers by assisting in their deployments, solutions or even at times their next generation solutions. All of these efforts allow me to stay in touch with various aspects of my industry that interest me, assist various levels of businesses to accomplish strategic goals, learn new, exciting and innovative ways to look at problems and solve them, and help with hands-on technology that I consider fun and intriguing.

Also in a prior post, I mentioned building my own personal technical environment with which to explore new technologies, build up my own knowledge, and not apply my own concepts to problems that may be of benefit to myself in my career but to others as well.

I look at things in terms of investments such as say learning Java. It is a pretty simple proposition to purchase a book, load the most popular software components such as the JVM, Maven, Eclipse, etc. and learn some of the concepts. Even purchasing a copy of VMware can help professionals gain a better understanding of virtualization. Using virtualized environments to help demonstrate how to spin up/spin down resources helps others to see practical benefits, considerations and how to apply that to their own environments. Ultimately what I attempt to do is motivate and inspire other professionals to do more with resources available to them. To think on their own and to grow on their own. Ultimately being able to rely on yourself, being active and focused, and learning new skills is a requirement in today's hyper-competitive landscape.

Thursday
Jan072010

Learning C++ - Who Says You Learn Nothing from Games?

Recently I have been involved in training and teaching my younger sibling and his friends programming. Not just any programming mind you, but game programming. Admittedly this effort is not full on programming, but rather programming basics with C++. What I find fascinating is why they want to learn - video games.

A big thing for video games nowadays is the concept of creating your own modifications to an existing game called "modding". This has been around for a while now with a lot of games having very strong communities around modifications. First-person shooting games such as Call of Duty and Counterstrike had many mods. However like anything else the games in today's world have come so very far in terms of mods.

One of the more interesting games with a very rich, and confusing, toolset is Dragon Age Origins from EA and Bioware. They have a social portal and a wiki for the many consumers of their game and the modders who want to create new content with them.

The toolset itself is a very rich and powerful platform with a lot of capabilities to create new experiences in the game. The toolset is 100% free to anyone who has a copy of the game. It comes with a very rich and powerful GUI and a lot of tools for models, skins, textures, etc. What is also very interesting is how the toolset introduces certain concepts such as code check-ins/check-outs, group modifications, methods on testing, creating sharable code/modules, etc. Many of these concepts are in fact quite common in today's developer organizations and are quite frankly not very well explored in many college classes. The fact that there is a global community of modders for Dragon Age like so many other games allows people to see how others view their work.

One of the most challenging aspects of Dragon Age is that it actually requires a certain degree of programming most notably C++ in what they call scripts. These are essentially pluggable code snippets that allow someone making a mod to do quite a few things.

For example let's say someone wants to add a newly created item to their character's inventory. One of the sites provides an excellent tutorial on how to do this. This example allows someone making a mod to build upon it accordingly.

// All module events
#include "utility_h"
#include "wrappers_h"
#include "events_h"
void main()
{
    event ev   = GetCurrentEvent();
    int nEvent = GetEventType(ev);
    Log_Events("", ev);
    switch (nEvent)
    {
        ////////////////////////////////////////////////////////////////////////
        // Sent by: The engine
        // When: The module loads from a save game, or for the first time. This event can fire more than
        //       once for a single module or game instance.
        ////////////////////////////////////////////////////////////////////////
        case EVENT_TYPE_MODULE_LOAD:
        {

            // get the object which contains the player
            object oPlayer = GetHero();

            // get the object which contains the item we are looking for
            object oCarmor = GetObjectByTag("alt_start_armor");
            object oCgloves = GetObjectByTag("alt_start_gloves");
            object oCboots = GetObjectByTag("alt_start_boots");
            object oCsword = GetObjectByTag("alt_start_sword");
            object oCshield = GetObjectByTag("alt_start_shield");

            if (!IsObjectValid(oCarmor))
                UT_AddItemToInventory(R"alt_start_armor.uti",1);

            if (!IsObjectValid(oCgloves))
                UT_AddItemToInventory(R"alt_start_gloves.uti",1);

            if (!IsObjectValid(oCboots))
                UT_AddItemToInventory(R"alt_start_boots.uti",1);

            if (!IsObjectValid(oCsword))
                UT_AddItemToInventory(R"alt_start_sword.uti",1);

            if (!IsObjectValid(oCshield))
                UT_AddItemToInventory(R"alt_start_shield.uti",1);


            // get out of case statement
            break;
        }
        default:
        {
            break;
        }
    }
}

 

Such scripts are actually used by the game engine itself to achieve certain goals such as those included in the core engine:

#include "ability_h"
#include "effects_h"
#include "events_h"
#include "config_h"
#include "ai_main_h_2"
#include "global_objects_h"
#include "sys_injury"
#include "sys_autoscale_h"
#include "sys_itemsets_h"
#include "sys_traps_h"
#include "approval_h"
#include "sys_autolevelup_h"
#include "sys_rewards_h"
#include "tutorials_h"

#include "plt_tut_combat_salve"
#include "plt_tut_fatigue"
#include "plt_tut_armor_archer"
#include "plt_tut_first_gift"

#include "stats_core_h"

const int APPROVAL_DEATH_PENALTY = -3;

void   _ScheduleResurrectionAttempt(object oCreature)
{
    DelayEvent(6.0f, oCreature, Event(EVENT_TYPE_PARTY_MEMBER_RES_TIMER));
}



// -----------------------------------------------------------------------------
// @brief: Post resurrection event. Trigger soundset on player, add injury and
// approval penalties
// @author: Georg
// -----------------------------------------------------------------------------
int HandleEvent_Resurrection(object oCreature, event ev)
{
    int bApplyInjury = GetEventInteger(ev,0);
    if (bApplyInjury)
    {
        PlaySoundSet(oCreature, SS_EXPLORE_HEAL_ME);
        Injury_DetermineInjury(oCreature);
    }

    // redo itemset bonuses
    ItemSet_Update(oCreature);

    // CUT!
    //int nFollower = Approval_GetFollowerIndex(OBJECT_SELF);
    //if(nFollower != -1)
    //    Approval_ChangeApproval(nFollower, APPROVAL_DEATH_PENALTY);

    return TRUE;

}

// -----------------------------------------------------------------------------
// Spawn Event Handler
//
// Purpose:
// -- Set Stats
// -- Add Abilities
//
// -----------------------------------------------------------------------------
int HandleEvent_Spawn(event ev);
int HandleEvent_Spawn(event ev)
{

    if (!IsHero(OBJECT_SELF))
    {
        AS_InitCreature(OBJECT_SELF);
    }
    else
    {
        // ---------------------------------------------------------------------
        // Hero character gets his heartbeat event initialized here.
        // Followers get theirs when they are hired.
        // ---------------------------------------------------------------------
        InitHeartbeat(OBJECT_SELF, CONFIG_CONSTANT_HEARTBEAT_RATE);
    }

    return TRUE;

}

// -----------------------------------------------------------------------------
// Perception Disappear Event Handler
// Parameters:
// -- Obj(0): Creature appearing
//
// Purpose:
// -- Ends Delayed shout loop
// -- Sets combat mode to false if no hostiles are around anymore
// -----------------------------------------------------------------------------
int HandleEvent_PerceptionDisappear(event ev);
int HandleEvent_PerceptionDisappear(event ev)
{

    object oDisappearer = GetEventObject(ev, 0); //GetEventCreator(ev);

    // -----------------------------------------------------------------
    // If we unperceive a hostile object, and it's the last perceived
    // hostile, drop out of combat.
    // -----------------------------------------------------------------
    if (IsObjectHostile(oDisappearer,OBJECT_SELF))
    {
        Combat_HandleCreatureDisappear(OBJECT_SELF, oDisappearer);
    }
    else if(!IsObjectValid(oDisappearer)) // For cases where creatures are destroyed when dead (spirit, explodes)
    {
        if (!IsPartyPerceivingHostiles(OBJECT_SELF))
        {

            if (!IsPartyDead())
            {
                #ifdef DEBUG
                Log_Trace(LOG_CHANNEL_COMBAT, "HandleEvent_PerceptionDisappear", "STOPPING COMBAT FOR PARTY!");
                #endif
               /* ResurrectPartyMembers();

                // ------------------------------------------------------------------
                // ... we switch the game back to explore mode.
                // Note: This switches CombatState on all party members as party of
                //       the GameModeChange Module Level Event
                // ------------------------------------------------------------------
                WR_SetGameMode(GM_EXPLORE);*/
                DelayEvent(1.0f, GetModule(), Event(EVENT_TYPE_DELAYED_GM_CHANGE));
            }
        }
    }

    // -------------------------------------------------------------
    // Event was fully handled, do not fall through to rules_core
    // -------------------------------------------------------------
    return TRUE;
}

// -----------------------------------------------------------------------------
// Item Equip Event Handler
// -- sets 'prefer ranged' flag is equipping a ranged weapon in the main hand
//
//  Params:
//      int (0) - the inventory slot the item was equipped to
//      obj (0) - the item
// -----------------------------------------------------------------------------
int HandleEvent_Equip(event ev);
int HandleEvent_Equip(event ev)
{
    object oItem = GetEventObject(ev, 0);
    int nEquipByPlayer = GetEventInteger(ev, 1);

    #ifdef DEBUG
    Log_Trace(LOG_CHANNEL_TEMP,"player_core","itm:" + ToString(oItem) +" abi:" + ToString(GetItemAbilityId(oItem)));
    #endif

    #ifdef SKYNET
    TrackItemEvent(GetEventType(ev),OBJECT_SELF,oItem);
    #endif

    // Handle Item Set Tracking here
    ItemSet_Update(OBJECT_SELF);

    if(nEquipByPlayer)
    {
        if(GetBaseItemType(oItem) == BASE_ITEM_TYPE_ARMOR_HEAVY ||
            GetBaseItemType(oItem) == BASE_ITEM_TYPE_ARMOR_LIGHT ||
            GetBaseItemType(oItem) == BASE_ITEM_TYPE_ARMOR_MASSIVE ||
            GetBaseItemType(oItem) == BASE_ITEM_TYPE_ARMOR_MEDIUM)
                WR_SetPlotFlag(PLT_TUT_FATIGUE, TUT_FATIGUE_1, TRUE);
        if(GetBaseItemType(oItem) == BASE_ITEM_TYPE_ARMOR_HEAVY ||
                GetBaseItemType(oItem) == BASE_ITEM_TYPE_ARMOR_MASSIVE)
                WR_SetPlotFlag(PLT_TUT_ARMOR_ARCHER, TUT_ARMOR_ARCHER_1, TRUE);
    }



     // ------------------------------------------------------------------------
     // Temporary item enchantment code
     // ------------------------------------------------------------------------
     int nSlot = GetEventInteger(ev,0);
     if (nSlot == INVENTORY_SLOT_MAIN || (nSlot == INVENTORY_SLOT_OFFHAND && GetItemType(oItem) == ITEM_TYPE_WEAPON_MELEE) )
     {
         if (HasEnchantments(OBJECT_SELF))
         {
             EffectEnchantment_HandleEquip(oItem, OBJECT_SELF);
         }
     }


     return FALSE; // FALSE IS IMPORTANT HERE! DO NOT CHANGE!
}


// -----------------------------------------------------------------------------
// Item UnEquip Event Handler
//
//  Params:
//      int (0) - the inventory slot the item was removed from
//      obj (0) - the item
// -----------------------------------------------------------------------------
int HandleEvent_UnEquip(event ev);
int HandleEvent_UnEquip(event ev)
{
    object oItem = GetEventObject(ev, 0);

    #ifdef SKYNET
    TrackItemEvent(GetEventType(ev),OBJECT_SELF,oItem);
    #endif

    // Handle Item Set Tracking here
    ItemSet_Update(OBJECT_SELF);


     // ------------------------------------------------------------------------
     // Temporary item enchantment code
     // ------------------------------------------------------------------------
     int nSlot = GetEventInteger(ev,0);
     if (nSlot == INVENTORY_SLOT_MAIN || (nSlot == INVENTORY_SLOT_OFFHAND && GetItemType(oItem) == ITEM_TYPE_WEAPON_MELEE) )
     {
        if (HasEnchantments(OBJECT_SELF))
         {
             EffectEnchantment_HandleUnEquip(oItem, OBJECT_SELF);
         }
     }

    // -------------------------------------------------------------------------
    // Disable modal abilities that have their condition changed.
    // #define ABILITY_CONDITION_NONE          0x0
    // #define ABILITY_CONDITION_MELEEWEAPON   0x1
    // #define ABILITY_CONDITION_SHIELD        0x2
    // #define ABILITY_CONDITION_RANGEDWEAPON  0x4
    // #define ABILITY_CONDITION_BEHINDTARGET  0x8
    // #define ABILITY_CONDITION_DUALWEAPONS 0x040
    // #define ABILITY_CONDITION_2HWEAPON 0x080

    // -------------------------------------------------------------------------
    int[] abi = GetConditionedAbilities(OBJECT_SELF, 0xC7);
    int nSize = GetArraySize(abi);
    int i;
    for (i = 0; i < nSize; i++)
    {
        Effects_RemoveUpkeepEffect(OBJECT_SELF,abi[i]);
    }


     if (nSlot == INVENTORY_SLOT_CHEST)
     {
         #ifdef DEBUG
         Log_Trace(LOG_CHANNEL_COMBAT_GORE,"player_core:HandleEquip", "All gore removed due to changing armor");
         #endif

        Gore_RemoveAllGore(OBJECT_SELF);
     }




     return FALSE; // FALSE IS IMPORTANT HERE! DO NOT CHANGE!
}

// -----------------------------------------------------------------------------
// Inventory Event Handler
// -- Does nothing right now
// -----------------------------------------------------------------------------

int HandleEvent_InventoryEvent(event ev);
int HandleEvent_InventoryEvent(event ev)
{
    int nEventType = GetEventType(ev);
    object oOwner = GetEventCreator(ev);
    object oItem = GetEventObject(ev, 0);

    // -------------------------------------------------------------------------
    // Georg: Stores process their inventory events immediately, even while the
    //        gamestate is paused. We need to pass this information on to
    //        any sub events generated by the equip script or they'll get
    //        queued up until after the UI quits, causing all kind of havok
    // -------------------------------------------------------------------------
    int bProcessImmediate = GetEventInteger(ev,0);


    switch(nEventType)
    {
        case EVENT_TYPE_INVENTORY_ADDED:
        {


            //If the item acquired has the ITEM_SEND_ACQUIRED_EVENT variable set,
            //send an event to the module so that custom scripting can be done.
            int bSendCampaignEvent = GetLocalInt(oItem, ITEM_SEND_ACQUIRED_EVENT);
            if ( bSendCampaignEvent != 0 )
            {
                SendEventCampaignItemAcquired(GetModule(), oItem, bProcessImmediate);
            }

            if(GetBaseItemType(oItem) == BASE_ITEM_TYPE_QUICK)
            {
                int nItemAbility = GetItemAbilityId(oItem);
                if(nItemAbility == ITEM_ABILITY_HEALING_SALVE ||
                   nItemAbility == ITEM_ABILITY_HEALING_SALVE_1 ||
                   nItemAbility == ITEM_ABILITY_HEALING_SALVE_2 ||
                   nItemAbility == ITEM_ABILITY_HEALING_SALVE_3 ||
                   nItemAbility == ITEM_ABILITY_HEALING_SALVE_4)
                    WR_SetPlotFlag(PLT_TUT_COMBAT_SALVE, TUT_COMBAT_SALVE_1, TRUE);
            }
            else if(GetBaseItemType(oItem) == BASE_ITEM_TYPE_GIFT)
                WR_SetPlotFlag(PLT_TUT_FIRST_GIFT, TUT_FIRST_GIFT_1, TRUE);

            break;
        }
        case EVENT_TYPE_INVENTORY_REMOVED:
        {

            // If the item removed has ITEM_SEND_LOST_EVENT set send the event.
            int bSendCampaignEvent = GetLocalInt( oItem, ITEM_SEND_LOST_EVENT );

            if ( bSendCampaignEvent )
                SendEventCampaignItemLost( GetModule(), oItem, bProcessImmediate );

            break;

        }
    }
    return TRUE;
}


// -----------------------------------------------------------------------------
// Death Event andler.
// Purpose:
// -- Clears AI target.
// -- Prints log message.
// -----------------------------------------------------------------------------
int HandleEvent_Death(event ev);
int HandleEvent_Death(event ev)
{
    // -------------------------------------------------------------------------
    // The death effect has been applied to this creature, either by losing hit points
    // or by explicit calling of the effect.
    // -------------------------------------------------------------------------
    object oKiller = GetEventCreator(ev);
    int    bPartyWipe = IsPartyDead();

    SetCreatureFlag(OBJECT_SELF,CREATURE_RULES_FLAG_DYING,FALSE);

    // -------------------------------------------------------------------------
    // SkyNet creature death tracking event.
    // -------------------------------------------------------------------------
    #ifdef SKYNET
    TrackObjectDeath(ev);
    #endif

    // -------------------------------------------------------------------------
    // Clear the object's perception list
    // -------------------------------------------------------------------------
    ClearPerceptionList(OBJECT_SELF);

    AI_Threat_UpdateDeath(OBJECT_SELF);

    // -------------------------------------------------------------------------
    // If the party was wiped, set gamemode dead.
    // -------------------------------------------------------------------------
    if (bPartyWipe)
    {

        int iDeathHint = GetLocalInt(GetModule(), DEATH_HINT);

        //If module variable "DEATH_HINT" is not zero, use it.
        if(iDeathHint != 0)
        {
            SetDeathHint(iDeathHint, 205);
        }
        else
        {
            //If DEATH_HINT is zero, use loop to determine statistics on party.
            object[] oParty = GetPartyList(GetHero());
            int nSize = GetArraySize(oParty);
            int i;
            int iLevelCounter;
//          int iTacticCounter;
//          int iStaminaCounter;
            object oCurrent;
            for(i = 0; i < nSize; i++)
            {
                oCurrent = oParty[i];
                if(GetCanLevelUp(oCurrent) == TRUE)
                {iLevelCounter += 1;}
            }
            //Fire if party member needs to level up.
            if(iLevelCounter > 0)
            {
                  SetDeathHint(2, 205);
            }else
            {
            //Random Death hint
                int iRows = GetM2DARows(272);
                int nRand = Random(iRows) + 1;
                nRand = GetM2DARowIdFromRowIndex(272, nRand);
                SetDeathHint(nRand, 272);
            }
            SetLocalInt(GetModule(), DEATH_HINT, 0);
        }

        #ifdef DEBUG
        Log_Trace(LOG_CHANNEL_COMBAT_DEATH, "player_core.HandleOnDeath","Everyone dead, changing game mode...");
        #endif
        WR_SetGameMode(GM_DEAD);
    }
    else
    {
        // ---------------------------------------------------------------------
        // handle any plot-specific logic for a follower death
        // currently needed only for Wynne's special ability
        // ---------------------------------------------------------------------
        SendModuleHandleFollowerDeath(OBJECT_SELF);

        SetCombatState(OBJECT_SELF,FALSE);

        // ---------------------------------------------------------------------
        // If we are in explore mode, schedule auto resurrection
        // ---------------------------------------------------------------------
        if (GetGameMode() == GM_EXPLORE)
        {
            //------------------------------------------------------------------
            // Sorry, summoned creatures can't be revived.
            //------------------------------------------------------------------
            if (!IsSummoned(OBJECT_SELF))
            {
                _ScheduleResurrectionAttempt(OBJECT_SELF);
            }
        }

        // ---------------------------------------------------------------------
        // This handles the 'party member slain' message;
        // ---------------------------------------------------------------------
        object[] aAlly = GetNearestObjectByGroup(OBJECT_SELF, GetGroupId(OBJECT_SELF), OBJECT_TYPE_CREATURE,1, 1, 0, 0);
        if (GetArraySize(aAlly)>0)
        {
            SSPlaySituationalSound(aAlly[0],SOUND_SITUATION_PARTY_MEMBER_SLAIN, oKiller);
        }

    }

    return TRUE;
}


// -----------------------------------------------------------------------------
// Load tactics event handler
// -- Currently this just uses a naive method to populate tactics with valid
// -- skills.
// -----------------------------------------------------------------------------
int HandleEvent_LoadTactics(object oCreature, event ev);
int HandleEvent_LoadTactics(object oCreature, event ev)
{
    int nPresetID = GetEventInteger(ev, 0);
    Chargen_LoadPresetsTable(oCreature, nPresetID);

    return TRUE;
}

// -----------------------------------------------------------------------------
// Use ability immediately.
// -- Some player abilities are used immediately, bypassing the ai command queue
// -- in order to process them while the game is paused.
// -- Currently this is only used for the crafting GUI.
// -----------------------------------------------------------------------------
int HandleEvent_UseAbilityImmediate(object oCreature, event ev);
int HandleEvent_UseAbilityImmediate(object oCreature, event ev)
{

    int nAbility = GetEventInteger(ev, 0);
    ShowCraftingGUI(nAbility);

    return TRUE;
}

void main()
{
    event ev = GetCurrentEvent();
    int nEventType = GetEventType(ev);

    // Setting this to true will prevent the script from invoking rules_core
    int bEventHandled = FALSE;

    // Prevent log spam
    #ifdef DEBUG
    if (nEventType != EVENT_TYPE_HEARTBEAT2)
        Log_Events("", ev);
    #endif

    switch(nEventType)
    {
        // ---------------------------------------------------------------------
        // Fired by engine when creature is spawned.
        // ---------------------------------------------------------------------
        case EVENT_TYPE_SPAWN:
        {
            // Only do this once...
            if(!GetLocalInt(OBJECT_SELF, CREATURE_SPAWNED))
            {
                SetLocalInt(OBJECT_SELF, CREATURE_SPAWNED, 1);
                bEventHandled = HandleEvent_Spawn(ev);
            }
            break;
        }

        // ---------------------------------------------------------------------
        // Handle Inventory Added / Removed Events
        //  Params:
        //      int (0) - the inventory slot the item added or removed from
        //      obj (0) - the item
        // ---------------------------------------------------------------------
        case EVENT_TYPE_INVENTORY_REMOVED:
        case EVENT_TYPE_INVENTORY_ADDED:
        {
            bEventHandled = HandleEvent_InventoryEvent(ev);
            break;
        }

        // ---------------------------------------------------------------------
        // Handle Perception Disappear Events
        // ---------------------------------------------------------------------
        case EVENT_TYPE_PERCEPTION_DISAPPEAR:
        {
            bEventHandled = HandleEvent_PerceptionDisappear(ev);
            break;
        }

        // -----------------------------------------------------------------
        // Damage over time tick event.
        // This is activated from EffectDOT and keeps rescheduling itself
        // while DOTs are in effect on the creature
        // -----------------------------------------------------------------
        case EVENT_TYPE_DOT_TICK:
        {
            if (!IsDead() && !IsDying())
            {
              Effects_HandleCreatureDotTickEvent();
            }

            bEventHandled = TRUE;
            break;
        }

        // ---------------------------------------------------------------------
        // @brief Heartbeat event generated by engine in response to InitHeartbeat()
        // ---------------------------------------------------------------------
        case EVENT_TYPE_HEARTBEAT2:
        {
             // No heartbeat for dead people
             if (IsDeadOrDying(OBJECT_SELF))
               return;

            // gradual mana/stamina regen in combat
            if(GetGameMode() == GM_COMBAT)
            {
                float fCurrentManaStamina = GetCurrentManaStamina(OBJECT_SELF);
                float fCurrentStaminaRegen = GetCreatureProperty(OBJECT_SELF, PROPERTY_ATTRIBUTE_REGENERATION_STAMINA_COMBAT, PROPERTY_VALUE_BASE);
                float fNewStaminaRegen = fCurrentStaminaRegen;
                if(fCurrentManaStamina <= 25.0) // fastest regen
                    fNewStaminaRegen = REGENERATION_STAMINA_COMBAT_DEFAULT + 3.5;
                else if(fCurrentManaStamina <= 50.0) // mid regen
                    fNewStaminaRegen = REGENERATION_STAMINA_COMBAT_DEFAULT + 1.0;

                else // more than 50 -> slowest regen
                    fNewStaminaRegen = REGENERATION_STAMINA_COMBAT_DEFAULT + 0.5;

                SetCreatureProperty(OBJECT_SELF, PROPERTY_ATTRIBUTE_REGENERATION_STAMINA_COMBAT, fNewStaminaRegen);
            }

            // Check for traps
            Trap_RunDetectionPulse(OBJECT_SELF);


            // Track movements for stats
          //  if (IsHero(OBJECT_SELF)) STATS_TrackWalkedDistance();


             // ----------------------------------------------------------------
             // Generate SkyNet Position Tracking Event
             // http://georg/SkyNetWeb - Talk to georg if you have questions
             // Note: For development telemetry only - will not work in SHIP exectuables.
             // ----------------------------------------------------------------
             #ifdef SKYNET
             if (IsHero(OBJECT_SELF))
             {
                TrackPos();
             }
             #endif

             if (LOG_ENABLED)
             {
                if (IsImmortal(OBJECT_SELF))
                {
                    command cCommand = GetCurrentCommand(OBJECT_SELF);
                    if(GetCommandType(cCommand) != 38) // death blow command (engine turns follower immortal during death blows)
                    {
                     //   Warning ("Warning: " + ToString(OBJECT_SELF) + " seems to be immortal, which is probably a bug. Hero tag: " + GetTag(GetHero())+"Please file a bug through SkyNet to Yaron");
                        DEBUG_PrintToScreen("Warning: PC object " + ToString(OBJECT_SELF) + " is immortal!", 15 + Random(2), 2.0f);
                    }
                }
                DEBUG_PrintToScreen("Difficulty " + ToString(GetGameDifficulty()) + "", 11, 2.0f);
             }


             bEventHandled = TRUE;
             break;
        }

        // -----------------------------------------------------------------
        // Legacy Heartbeat event. Left for the consumption of modders.
        // Be careful with it, it's not nice to run on a lot of creatures...
        // -----------------------------------------------------------------
        case EVENT_TYPE_HEARTBEAT:
        {
             bEventHandled = TRUE;
             break;
        }

        case EVENT_TYPE_EQUIP:
        {
            bEventHandled = HandleEvent_Equip(ev);
            break;
        }

        case EVENT_TYPE_UNEQUIP:
        {
            bEventHandled = HandleEvent_UnEquip(ev);
            break;
        }

        // ---------------------------------------------------------------------
        // Fires first time a party member is added to the party
        // For plot followers: follower recruited (added to pool)
        // For other followers: UT_Hire called
        // Owner: Yaron
        // ---------------------------------------------------------------------
        case EVENT_TYPE_PARTY_MEMBER_HIRED:
        {
            int nScaled = GetLocalInt(OBJECT_SELF, FOLLOWER_SCALED);
            int nShowPartyPicker = GetEventInteger(ev, 0);
            int nMinLevel = GetEventInteger(ev, 1);
            int bPreventLevelup = GetEventInteger(ev, 2);

            #ifdef DEBUG
            Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                "show party picker: " + IntToString(nShowPartyPicker));
            #endif

            int bSummoned  =  IsSummoned(OBJECT_SELF);

            // -----------------------------------------------------------------
            // @author georg Initialize Follower Heartbeat.
            // Note: This is terminated in EVENT_TYPE_PARTY_MEMBER_FIRED.
            // -----------------------------------------------------------------
            if (!bSummoned)
            {
                // Heartbeat check moved to WR_SetFollowerState
                //InitHeartbeat(OBJECT_SELF, CONFIG_CONSTANT_HEARTBEAT_RATE);

                // checking tactics presets
                // It is fine to do this more than once
                Chargen_EnableTacticsPresets(OBJECT_SELF);
            }

            // -----------------------------------------------------------------
            // @author yaron
            // This can fire only once - when first hired
            // -----------------------------------------------------------------
            if(!nScaled && !bSummoned && !IsHero(OBJECT_SELF))
            {
                SetLocalInt(OBJECT_SELF, FOLLOWER_SCALED, 1);
                int nPackage = GetPackage(OBJECT_SELF);
                int nPackageClass = GetM2DAInt(TABLE_PACKAGES, "StartingClass", nPackage);


                // set behavior
                int nBehavior = GetM2DAInt(TABLE_PACKAGES, "FollowerBehavior", nPackage);
                if(nBehavior >= 0)
                    SetAIBehavior(OBJECT_SELF, nBehavior);

                // -------------------------------------------------------------
                // <scaling>
                //
                // NOTE: creature was scaled already in creature_core - in here
                // we clear him completely and reconstruct from scratch
                // -------------------------------------------------------------
                Chargen_InitializeCharacter(OBJECT_SELF);

                // -------------------------------------------------------------
                // Apply race and class modifiers.
                // -------------------------------------------------------------
                Chargen_SelectRace(OBJECT_SELF,GetCreatureRacialType(OBJECT_SELF));
                Chargen_SelectCoreClass(OBJECT_SELF,GetCreatureCoreClass(OBJECT_SELF));

                // -------------------------------------------------------------
                // yaron: Scale followers to level.
                // -------------------------------------------------------------
                int nTargetLevel;
                int nPlayerLevel = GetLevel(GetHero());
                if(nPlayerLevel >= 13 || nPlayerLevel == 1 || !_UT_GetIsPlotFollower(OBJECT_SELF))
                    nTargetLevel = nPlayerLevel;
                else
                    nTargetLevel = nPlayerLevel + 1;
                int nMinLevel = GetM2DAInt(TABLE_PACKAGES, "MinLevel", nPackage);
                if(nMinLevel > 0 && nMinLevel > nTargetLevel)
                    nTargetLevel = nMinLevel;
                #ifdef DEBUG
                Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                        "Target level: " + IntToString(nTargetLevel));
                #endif

                if(nPackageClass != CLASS_MONSTER_ANIMAL)
                {
                    // -------------------------------------------------------------
                    // Follower leveled one level higher than the player unless the player
                    // is too high level.
                    // -------------------------------------------------------------

                    int nXp = RW_GetXPNeededForLevel(Max(nTargetLevel, 1));

                    #ifdef DEBUG
                    Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                            "Giving XP: " + IntToString(nXp));
                    #endif

                    int nState = GetFollowerState(OBJECT_SELF);
                    string sFollowerState = _GetFollowerStateName(nState);

                    #ifdef DEBUG
                    Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                            "Follower state: " + sFollowerState);
                    #endif
                    RewardXP(OBJECT_SELF, nXp, FALSE, FALSE);
                }

                // -------------------------------------------------------------
                // add hidden approval talents
                // -------------------------------------------------------------
                int nIndex = Approval_GetFollowerIndex(OBJECT_SELF);
                Approval_AddFollowerBonusAbility(nIndex, 0);

                // Find specialization
                int nSpecAbility = GetM2DAInt(TABLE_PACKAGES, "switch1_class", nPackage); // followers can have only 1 advanced class
                if(nSpecAbility > 0)
                {
                    #ifdef DEBUG
                    Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                        "Adding spec ability: " + IntToString(nSpecAbility));
                    #endif
                    AddAbility(OBJECT_SELF, nSpecAbility);
                }

                // -------------------------------------------------------------
                // This spends all available attribute and stat points on the
                // creature according to the levelup table.
                // -------------------------------------------------------------

                AL_DoAutoLevelUp(OBJECT_SELF, TRUE);

                if(bPreventLevelup)
                {
                    #ifdef DEBUG
                    Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                        "Preventing creature from levelling up");
                    #endif
                    SetLocalInt(OBJECT_SELF, CREATURE_REWARD_FLAGS, 1);
                }

                // load tactics
                int nTableID = GetM2DAInt(TABLE_PACKAGES, "FollowerTacticsTable", nPackage);
                if (nTableID != -1)
                {
                    #ifdef DEBUG
                    Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                        "Loading follower tactics from table: " + IntToString(nTableID));
                    #endif
                    int nRows = GetM2DARows(nTableID);
                    int nMaxTactics = GetNumTactics(OBJECT_SELF);
                    #ifdef DEBUG
                    Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                        "Loading follower tactics from table: " + IntToString(nTableID) + ", row: " + IntToString(nRows));
                    #endif

                    int nTacticsEntry = 1;
                    int i;
                    for (i = 1; i <= nRows && nTacticsEntry <= nMaxTactics; ++i)
                    {
                        int bAddEntry = FALSE;
                        int nTargetType = GetM2DAInt(nTableID, "TargetType", i);
                        int nCondition = GetM2DAInt(nTableID, "Condition", i);
                        int nCommandType = GetM2DAInt(nTableID, "Command", i);
                        int nCommandParam = GetM2DAInt(nTableID, "SubCommand", i);

                        #ifdef DEBUG
                        Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                            "adding tactics: " + IntToString(i));
                        #endif
                        int nUseType = GetM2DAInt(TABLE_COMMAND_TYPES, "UseType", nCommandType);
                        if (nUseType == 0)
                        {
                            bAddEntry = TRUE;
                        }
                        else
                        {
                            bAddEntry = HasAbility(OBJECT_SELF, nCommandParam);
                        }

                        if (bAddEntry)
                        {
                            SetTacticEntry(OBJECT_SELF, nTacticsEntry, TRUE, nTargetType, nCondition, nCommandType, nCommandParam);
                            ++nTacticsEntry;
                        }
                    }
                }

                // @author yaron
                // DEBUG - scale items
                #ifdef DEBUG
                if(GetLocalInt(GetModule(), DEBUG_ENABLE_PARTY_ITEM_SCALING) == 1)
                {

                    Log_Trace(LOG_CHANNEL_EVENTS, "player_core.EVENT_TYPE_PARTY_MEMBER_HIRED",
                        "DEBUG - scaling items - THIS CODE SHOULD NOT RUN NORMALLY");
                    DEBUG_ScaleFolloweItems(OBJECT_SELF);
                }
                #endif
                //if this is Alistair - show the tutorial
                if (GetTag(OBJECT_SELF) == "gen00fl_alistair")
                {
                    BeginTrainingMode(TRAINING_SESSION_FOLLOWERS_AND_TACTICS);
                }
            }

            if(nShowPartyPicker && GetLocalInt(GetArea(OBJECT_SELF), AREA_DEBUG) == FALSE)
            {
                SetPartyPickerGUIStatus(PP_GUI_STATUS_USE);
                ShowPartyPickerGUI();
            }

            bEventHandled = TRUE;
            break;
        }


        // ---------------------------------------------------------------------
        // Fires an active or locked-active party member is removed from the
        // active party
        // ---------------------------------------------------------------------
        case EVENT_TYPE_PARTY_MEMBER_FIRED:
        {
            // NOTE: this event actually does not fire in many cases
            // follower-fired code in better put in WR_SetFollowerState

            break;
        }

        // ---------------------------------------------------------------------
        // Sent by engine when henchman or player is selected.
        // ---------------------------------------------------------------------
        case EVENT_TYPE_ON_SELECT:
        {
            SSPlaySituationalSound(OBJECT_SELF, SOUND_SITUATION_SELECTED);
            bEventHandled = TRUE;
            break;
        }

        // ---------------------------------------------------------------------
        // Sent by engine when henchman or player is given an order.
        // ---------------------------------------------------------------------
/*        case EVENT_TYPE_ON_ORDER_RECEIVED:
        {
            SSPlaySituationalSound(OBJECT_SELF, SOUND_SITUATION_ORDER_RECEIVED,GetEventTarget(ev));
            bEventHandled = TRUE;
            break;
        }*/
        case 94 : /*EVENT_TYPE_PLAYER_COMMAND_ADDED:*/
        {
            SSPlaySituationalSound(OBJECT_SELF, SOUND_SITUATION_ORDER_RECEIVED, GetEventTarget(ev), GetEventInteger(ev, 0));
            bEventHandled = TRUE;
            break;
        }




        // ---------------------------------------------------------------------
        // Sent by engine when creature is killed.
        // ---------------------------------------------------------------------
        case EVENT_TYPE_DEATH:
        {
            bEventHandled = HandleEvent_Death(ev);
            break;
        }

        // ---------------------------------------------------------------------
        // Resurrection timer used if a creature dies in explore mode.
        // ---------------------------------------------------------------------
        case EVENT_TYPE_PARTY_MEMBER_RES_TIMER:
        {
            if (GetGameMode() == GM_EXPLORE)
            {
                ResurrectCreature(OBJECT_SELF);
            }
            break;
        }

        // ---------------------------------------------------------------------
        // Creature is resurrected. Fired by effect_resurrection.OnApply
        // ---------------------------------------------------------------------
        case EVENT_TYPE_RESURRECTION:
        {
            bEventHandled = HandleEvent_Resurrection(OBJECT_SELF, ev);
            break;
        }

        // ---------------------------------------------------------------------
        // Creature is spawned. Fired by sys_rewards_h.RewardXP
        // ---------------------------------------------------------------------
        case EVENT_TYPE_PLAYER_LEVELUP:
        {
            #ifdef SKYNET
            TrackPartyMemberEvent(nEventType, OBJECT_SELF, OBJECT_INVALID, GetLevel(OBJECT_SELF));
            #endif

            UI_DisplayMessage(OBJECT_SELF, UI_MESSAGE_LEVELUP);
            break;
        }

        case EVENT_TYPE_LOAD_TACTICS_PRESET:
        {
            bEventHandled = HandleEvent_LoadTactics(OBJECT_SELF, ev);
            break;
        }

        //----------------------------------------------------------------------
        // Sent by engine when player clicks on object.
        //----------------------------------------------------------------------
        case EVENT_TYPE_PLACEABLE_ONCLICK:
        {
            // Pass event along to the placeable being clicked on.
            SignalEvent(GetEventTarget(ev), ev);
            bEventHandled = TRUE;
            break;
        }

        case EVENT_TYPE_USE_ABILITY_IMMEDIATE:
        {
            bEventHandled = HandleEvent_UseAbilityImmediate(OBJECT_SELF, ev);
            break;
        }

    }


    if (!bEventHandled)
    {
        HandleEvent(ev, RESOURCE_SCRIPT_RULES_CORE);
    }
}

 

What is really fascinating is the motivation to learn. The modders get to see the results of what they do right away. In certain cases they get to see what many people have to say. They also learn what certain programmatic approaches do and why they are used. The game serves as a practical and more importantly a relatable means of applying what they learn.

In many cases this is one the most crucial items lacking in many organizations and from many professionals trying to teach programming to up and coming individuals. Their inability to relate concepts to others is what drives much of the barrier to collaboration and cooperation. And from my experience, many large organizations simply find excuses not to pursue better approaches because they simply do not know how to do so or do not have the desire to do so.

In any event I find it very comforting to know that there are probably quite a few talented individuals coming up in the technology field from a wide and varied background. I also like the fact that video games have a lot to teach people about computer programming and science than what most people think.

Wednesday
Jan062010

2010 - I Predict as "The Year of Innovation"

As the overall economy starts to recover, there are signs of improvement everywhere. Admittedly we have a long way to go but recent stories about various innovations are proving that the year 2010 will be definitely a great year.

Why do I think this? Well there are the big items of course such as the new Google Nexus One, the rumors of the Apple tablet, and many other wonderful things being unveiled at CES. These innovations are fundamentally changing the markets, the consumer experience, and the professional lives of the men and women working in these areas. They are achieving this in spite of being in one of the worse economic times in history. Where many larger brand names have been solely focusing on the typical management cost controls (i.e. layoffs, etc.) more forward thinking companies like Google and Apple have been creating new value propositions that are poised to take off. This sort of activity fundamentally differentiates the leaders and innovators, from the status quo.

However it is not only the larger names making impacts. Smaller and younger companies are also making names for themselves in areas that were not conceived of more than a few short years ago. Some examples are AteBits, Inc., Card.ly, Seesmic, and CitySourced to name a few. All of these companies emerged during difficult economic times, using extraordinary vision and innovation, making simple and powerful services, and on budgets that in many cases amounted to far less than the office supply allowances for many large companies.

The economic downturn has convinced many that their personal and professional lives are truly in their own hands and as such they have started to create value on their own. However lead by a new way of creating value for their products via mechanisms like Amazon Web Services, Apple's App Store, Android App Store and Twitter's Open APIs, many new companies and brands are emerging by leveraging the offerings created by these companies to create their own unique value. The men and women taking this approach are intelligent, driven, insightful and highly skilled learning what they need as they go which makes them excellent professionals not only for what they do now but what they are doing in the future.

It is through the circumstance of a bad economy that has fueled this engine of innovation and professional growth. Given the amount of time it will take the economy to recover and the amount of people taking this course, this is creating a whole new workforce and opportunity that will fundamentally change how businesses operate in the future. Let's take the telecom/handset/mobile space. Why would talent want to work for the traditional status quo providers when all the opportunity, excitement and innovation is occurring in the new areas created by Apple and Google? The cost of entry is low, the rewards very high, and far more satisfying than working with any larger company. In many cases the same cost cutting and "hunker down" attitudes have come at immeasurable cost of talent acquisition. Most talented individuals no longer see working at the existing companies as being in their best interests. This will take

It will be interesting to see how the existing companies see these changes and how long they wait to adjust to them. After all, they are being outmaneuvered right now at a time that challenges the core of who they are. And in my opinion many existing companies are either dying by inches or barely holding on whereas their more innovative counterparts are thriving and growing. 2010 will indeed be an interesting year!