source: scenarios/GerminationX/fungi/src/Fungi.hx @ 999

Revision 999, 19.0 KB checked in by dave, 9 years ago (diff)

remote update of characters, auto polling

Line 
1// GerminationX Copyright (C) 2010 FoAM vzw    \_\ __     /\
2//                                          /\    /_/    / / 
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Affero General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Affero General Public License for more details.
12//
13// You should have received a copy of the GNU Affero General Public License
14// along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16import haxe.Log;
17
18import truffle.Truffle;
19import truffle.interfaces.Key;
20
21import truffle.Vec3;
22import truffle.Vec2;
23import truffle.RndGen;
24import truffle.Circle;
25import truffle.Entity;
26import truffle.SpriteEntity;
27import truffle.SkeletonEntity;
28import truffle.Bone;
29
30import Critters;
31
32// todo: remove this
33import flash.display.Graphics;
34import flash.display.Shape;
35
36 
37//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38
39class Cube extends SpriteEntity
40{       
41        public function new(world:World, pos:Vec3)
42        {
43                super(world, pos, Resources.Get("blue-cube"));
44        }
45       
46        public function UpdateTex(rnd:RndGen)
47        {
48                if (LogicalPos.z%2==0)
49        {
50            Spr.ChangeBitmap(Resources.Get(
51                rnd.Choose(["rock-cube-01","rock-cube-02","rock-cube-03"])));
52                }
53                else
54                {
55            Spr.ChangeBitmap(Resources.Get(
56                rnd.Choose(["rock-cube-04","rock-cube-05","rock-cube-06"])));
57        }
58        }
59}
60
61//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62
63class Plant extends SpriteEntity
64{
65        public var Owner:String;
66        var PlantScale:Float;
67        public var Age:Int;
68    var Scale:Float;
69    var PlantType:String;
70    var State:String;
71    var Seeds:Array<Sprite>;
72    var Layer:String;
73
74        public function new(world:World, owner:String, pos, type:String, state:String)
75        {
76                super(world,pos,Resources.Get(type+"-"+state),false);
77        PlantType=type;
78        State=state;
79                Owner=owner;
80        PlantScale=0;
81        //NeedsUpdate=true;
82        Seeds=[];
83
84        Layer="none";
85        if (type=="plant-001") Layer="cover";
86        if (type=="plant-002") Layer="canopy";
87        if (type=="plant-003") Layer="vertical";
88
89        Spr.Hide(false);
90       
91        var tf = new flash.text.TextField();
92        tf.text = "This plant belongs to the "+type+" species, part of the "+
93            Layer+" layer. "+Owner+" planted this.";
94        tf.x=Spr.Pos.x-50;
95        tf.y=Spr.Pos.y-30-Spr.Height*Spr.MyScale.y;
96        tf.height=40;
97        tf.background = true;
98        //tf.backgroundColor = 0x8dd788;
99        tf.border = true;
100        tf.wordWrap = true;
101        tf.autoSize = flash.text.TextFieldAutoSize.LEFT;
102        var t = new flash.text.TextFormat();
103        t.font = "Verdana";
104        t.size = 8;               
105        t.color= 0x000000;           
106        tf.setTextFormat(t);
107        Spr.parent.addChild(tf);
108        tf.visible=false;
109        Spr.MouseOver(this,function(c) { tf.visible=true; });
110        Spr.MouseOut(this,function(c) { tf.visible=false; });
111        }
112
113    public function StateUpdate(state,world:World)
114    {
115        State=state;
116        if (State!="decayed")
117        {
118            Spr.ChangeBitmap(Resources.Get(PlantType+"-"+State));
119        }
120        if (State=="fruit-c" && Seeds.length==0)
121        {
122            Fruit(world);
123        }
124    }
125
126    override function Destroy(world:World)
127    {
128        super.Destroy(world);
129        for (seed in Seeds)
130        {
131            world.RemoveSprite(seed);
132        }
133    }
134       
135        public override function Update(frame:Int, world:World)
136        {
137                super.Update(frame,world);
138        }
139
140    public function Fruit(world:World)
141    {
142        var f=new Sprite(Spr.Pos.Add(new Vec2(0,-Spr.Height/2)),
143                         Resources.Get("seed"));
144        world.AddSprite(f);
145        Seeds.push(f);
146        f.MouseDown(this,function(p)
147        {           
148            if (world.MyName!="")
149            {
150                var s=new Seed(p.PlantType);
151                if (world.Seeds.Add(world,s))
152                {
153                    p.Seeds.remove(f);
154                    world.RemoveSprite(f);
155                }
156            }
157        });
158    }
159}
160
161//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162
163class Spirit extends SkeletonEntity
164{
165    public var Name:String;
166
167    var Debug:flash.text.TextField;
168        var BG:Graphics;
169    var RawEmotions:Dynamic;
170    var Emotions:Dynamic;
171    var DesiredPos:Vec2;
172    public var LastData:Array<Dynamic>;
173   
174        public function new(world:World, name:String, pos)
175        {
176                super(world,pos);
177        Name = name;
178        Speed=0.1;
179        UpdateFreq=5;
180        Hide(true);
181        LastData=[];
182        DesiredPos=new Vec2(LogicalPos.x,LogicalPos.y);
183        RawEmotions={Love:0,Hate:0,Hope:0,Fear:0,Satisfaction:0,
184                     Relief:0,/*Fears_Confirmed:0,*/Disappointment:0,
185                     Joy:0,Distress:0,/*Happy_For:0,*/Pitty:0,
186                     Resentment:0,Gloating:0,Pride:0,Shame:0,
187                     Gratification:0,Remorse:0,Admiration:0,
188                     Reproach:0,Gratitude:0,Anger:0};
189        Emotions={Love:0,Hate:0,Hope:0,Fear:0,Satisfaction:0,
190                  Relief:0,/*Fears_Confirmed:0,*/Disappointment:0,
191                  Joy:0,Distress:0,/*Happy_For:0,*/Pitty:0,
192                  Resentment:0,Gloating:0,Pride:0,Shame:0,
193                  Gratification:0,Remorse:0,Admiration:0,
194                  Reproach:0,Gratitude:0,Anger:0};
195    }
196
197        public function BuildDebug(c)
198    {
199        var tf = new flash.text.TextField();
200        tf.text = "nowt yet.";
201        tf.x=Pos.x-150;
202        tf.y=Pos.y-25;
203        tf.height=150;
204        tf.width=140;
205        tf.background = false;
206        tf.autoSize = flash.text.TextFieldAutoSize.LEFT;
207        //tf.backgroundColor = 0x8dd788;
208        tf.border = true;
209        tf.wordWrap = true;
210        var t = new flash.text.TextFormat();
211        t.font = "Verdana";
212        t.size = 8;               
213        t.color= 0x000000;           
214        tf.setTextFormat(t);
215
216        var figures:Shape = new Shape();
217        BG = figures.graphics;
218        BG.beginFill(0xffffff,0.5);
219        BG.drawRect(tf.x,tf.y,tf.width,tf.height);
220        BG.endFill();
221        figures.visible=false;
222        cast(c,truffle.flash.FlashWorld).addChild(figures);
223
224        c.addChild(tf);
225        Debug=tf;
226        tf.visible=false;
227
228        Root.MouseDown(c,function(c)
229        {
230            tf.visible=!tf.visible;
231            figures.visible=!figures.visible;
232        });
233        }
234
235    public function UpdateEmotions(e:Dynamic,world:World)
236    {
237        SetTilePos(new Vec2(Std.parseInt(e.tile.x),
238                            Std.parseInt(e.tile.y)));
239
240       
241        var dst = new Vec2(Std.parseInt(e.emotionalloc.x),
242                              Std.parseInt(e.emotionalloc.y));
243
244        if (dst.x!=DesiredPos.x || dst.y!=DesiredPos.y)
245        {
246            DesiredPos = dst;
247            while (world.Get("Spirit",dst)!=null)
248            {
249                dst = dst.Add(new Vec2(world.MyRndGen.Choose([-2,0,2]),
250                                       world.MyRndGen.Choose([-2,0,2])));
251            }
252            LogicalPos = new Vec3(dst.x,dst.y,4);
253        }
254
255        RawEmotions = e.emotions;
256
257        var ee = e.fatemotions.content;
258        var mood=Std.parseFloat(ee[0].content[0]);
259
260        var text=Name+"\nMood:"+ee[0].content[0]+"\n";
261        text+="Emotions:\n";
262        for (i in 1...ee.length)
263        {
264            text+=ee[i].attrs.type+" "+ee[i].attrs.direction+"\n";
265            //text+=ee[i].attrs.cause+"\n";
266        }
267
268        text+="Actions:\n";
269        var acs = cast(e.fatactions,Array<Dynamic>);
270        for (i in 0...acs.length)
271        {
272            text+=acs[i].msg+"\n";
273        }
274
275        Debug.text=text;
276
277        var t = new flash.text.TextFormat();
278        t.font = "Verdana";
279        t.size = 8;               
280        t.color= 0x000000;           
281        Debug.setTextFormat(t);
282        Debug.x=Pos.x-150;
283        Debug.y=Pos.y-25;
284
285        BG.clear();
286        BG.beginFill(0xffffff,0.5);
287        BG.drawRect(Debug.x,Debug.y,Debug.width,Debug.height);
288        BG.endFill();
289
290        //trace(text);
291    }
292
293    override function Update(frame:Int, world:World)
294    {
295        for (f in Reflect.fields(Emotions))
296        {
297            // do a linear blend to smooth out changes in emotions
298            Reflect.setField(Emotions,f,
299            Reflect.field(Emotions,f)*0.95+Reflect.field(RawEmotions,f)*0.05);
300            //trace(f);
301        }
302
303        //Draw(cast(world,truffle.World));
304        var c=this;
305        Root.Recurse(function(b:Bone,depth:Int)
306        {
307            var excitement = c.Emotions.Love+c.Emotions.Admiration;
308            if (excitement>10) excitement=10;
309           
310            b.SetRotate(excitement*5*Math.sin(
311                             (((10-depth)+frame*0.04+c.Emotions.Gratitude*0.01)+
312                             c.Emotions.Joy*0.1)) +
313            ((world.MyRndGen.RndFlt()-0.5)*10*(c.Emotions.Hate+
314                    c.Emotions.Distress)));
315           
316        });
317
318        super.Update(frame,world);
319    }
320}
321
322//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
323
324class Seed
325{
326    public var Type:String;
327    public var Spr:Sprite;
328
329    public function new(t:String)
330    {
331        Type=t;
332        Spr=new Sprite(new Vec2(0,0),Resources.Get("seed"));
333    }
334}
335
336class SeedStore
337{
338    var Seeds:Array<Seed>;
339    var Size:Int;
340
341    public function new(size:Int)
342    {
343        Seeds = [];
344        Size = size;
345    }
346
347    public function Add(world:World,s:Seed) : Bool
348    {
349        if (Seeds.length<Size)
350        {
351            Seeds.push(s);
352            s.Spr.SetPos(new Vec2(20+Seeds.length*10,30));
353            //cast(world,truffle.flash.FlashWorld).addSprite(s.Spr);
354            //trace("did it...");
355            s.Spr.Update(0,null);
356            return true;
357        }
358        return false;
359    }
360
361    public function Remove(world:World) : String
362    {
363        if (Seeds.length>0)
364        {
365            var s = Seeds.pop();
366//            world.RemoveSprite(s.Spr);
367            return s.Type;
368        }
369        else
370        {
371            return "";
372        }
373    }
374}
375
376//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
377
378class FungiWorld extends World
379{
380        public var Width:Int;
381        public var Height:Int;
382        var Objs:Array<Cube>;
383        public var WorldPos:Vec3;
384        var MyRndGen:RndGen;
385        public var MyTextEntry:TextEntry;
386        public var Plants:Array<Plant>;
387    public var TheCritters:Critters;
388        var MyName:String;
389    var Frame:Int;
390    var TickTime:Int;
391    var PerceiveTime:Int;
392    var Spirits:Array<Spirit>;
393    public var Seeds:SeedStore;
394    var Server : ServerConnection;
395
396        public function new(w:Int, h:Int)
397        {
398                super();
399                Frame=0;
400        TickTime=0;
401        PerceiveTime=0;
402                Width=w;
403                Height=h;
404                Plants = [];
405        Objs = [];
406        Spirits = [];
407        Seeds = new SeedStore(1);
408                WorldPos = new Vec3(0,0,0);
409                MyRndGen = new RndGen();
410        Server = new ServerConnection();
411        MyName = "";
412
413
414        var arrow1 = new SpriteEntity(this,new Vec3(7,-2,1), Resources.Get("arr3"));
415        arrow1.Spr.MouseUp(this,function(c) { c.UpdateWorld(c.WorldPos.Add(new Vec3(0,-1,0))); });
416        arrow1.Spr.MouseOver(this,function(c) { arrow1.Spr.SetScale(new Vec2(1.1,1.1)); arrow1.Spr.Update(0,null); });
417        arrow1.Spr.MouseOut(this,function(c) { arrow1.Spr.SetScale(new Vec2(1,1)); arrow1.Spr.Update(0,null); });
418 
419        var arrow2=new SpriteEntity(this,new Vec3(10,21,1), Resources.Get("arr4"));
420        arrow2.Spr.MouseUp(this,function(c) { c.UpdateWorld(c.WorldPos.Add(new Vec3(0,1,0))); });
421        arrow2.Spr.MouseOver(this,function(c) { arrow2.Spr.SetScale(new Vec2(1.1,1.1)); arrow2.Spr.Update(0,null); });
422        arrow2.Spr.MouseOut(this,function(c) { arrow2.Spr.SetScale(new Vec2(1,1)); arrow2.Spr.Update(0,null); });
423 
424        var arrow3=new SpriteEntity(this,new Vec3(-2,7,1), Resources.Get("arr2"));
425        arrow3.Spr.MouseUp(this,function(c) { c.UpdateWorld(c.WorldPos.Add(new Vec3(-1,0,0))); });
426        arrow3.Spr.MouseOver(this,function(c) { arrow3.Spr.SetScale(new Vec2(1.1,1.1)); arrow3.Spr.Update(0,null); });
427        arrow3.Spr.MouseOut(this,function(c) { arrow3.Spr.SetScale(new Vec2(1,1)); arrow3.Spr.Update(0,null); });
428
429        var arrow4=new SpriteEntity(this,new Vec3(20,10,1), Resources.Get("arr1"));
430        arrow4.Spr.MouseUp(this,function(c) { c.UpdateWorld(c.WorldPos.Add(new Vec3(1,0,0))); });
431        arrow4.Spr.MouseOver(this,function(c) { arrow4.Spr.SetScale(new Vec2(1.1,1.1)); arrow4.Spr.Update(0,null); });
432        arrow4.Spr.MouseOut(this,function(c) { arrow4.Spr.SetScale(new Vec2(1,1)); arrow4.Spr.Update(0,null); });
433
434                for (y in 0...h)
435                {
436                        for (x in 0...w)
437                        {
438                                var ob:Cube = new Cube(this,new Vec3(0,0,0));
439             
440                ob.Spr.MouseDown(this,function(c)
441                {
442                    var type=c.Seeds.Remove(cast(c,truffle.World));
443                    if (type!="")
444                    {
445                        c.AddServerPlant(ob.LogicalPos.Add(new Vec3(0,0,1)),type);
446                    }
447                });
448                                Objs.push(ob);
449                        }
450                }
451
452                UpdateWorld(new Vec3(0,0,0));
453               
454                MyTextEntry=new TextEntry(300,10,310,30,NameCallback);
455                addChild(MyTextEntry); 
456
457        TheCritters = new Critters(this,3);
458
459        Update(0);
460        SortScene();
461        var names = ["CanopySpirit","VerticalSpirit","CoverSpirit"];
462        var positions = [new Vec3(0,5,4), new Vec3(7,0,4), new Vec3(2,10,4)];
463
464        for (i in 0...3)
465        {
466            Server.Request("spirit-sprites/"+names[i],
467            this,
468            function (c,data:Array<Dynamic>)
469            {
470                var sp:Spirit = new Spirit(c,names[i],positions[i]);
471                sp.NeedsUpdate=true;
472                sp.LastData=data;
473                sp.Build(c,data);
474                sp.BuildDebug(c);
475                c.SortScene();
476                c.Spirits.push(sp);
477            });
478        }
479        }
480
481    function CompareLists(a:Array<Dynamic>,b:Array<Dynamic>): Bool
482    {
483        if (a.length!=b.length) return false;
484        for (i in 0...a.length)
485        {
486            if (a[i].name!=b[i].name) return false;
487        }
488        return true;
489    }
490
491    public function UpdateSpiritSprites()
492    {
493        for (s in Spirits)
494        {
495            Server.Request("spirit-sprites/"+s.Name,
496            this,
497            function (c,data:Array<Dynamic>)
498            {
499                if (!c.CompareLists(data,s.LastData))
500                {
501                    s.Build(cast(c,World),data);
502                    s.LastData=data;
503                }
504            });
505        }       
506    }
507       
508        public function NameCallback(name)
509        {
510                removeChild(MyTextEntry);
511                MyName=name;
512                //WorldClient.GetPlants(cast(WorldPos.x,Int),cast(WorldPos.y,Int));
513        }
514       
515        public function UpdateWorld(pos:Vec3)
516        {
517                WorldPos=pos;
518        SetCurrentTilePos(new Vec2(pos.x,pos.y));
519               
520                var circles = [];
521        for (x in -1...2)
522                {
523                        for (y in -1...2)
524                        {
525                                MyRndGen.Seed(cast((WorldPos.x+x)+(WorldPos.y+y)*139,Int));
526                                for (i in 0...5)
527                                {
528                                        var pos = new Vec3(MyRndGen.RndFlt()*15+x*15,
529                                       MyRndGen.RndFlt()*15+y*15,
530                                                                           0);           
531                                        circles.push(new Circle(pos, MyRndGen.RndFlt()*4));
532                                }
533                        }
534                }
535               
536               
537                for (i in 0...Objs.length)
538                {
539                        var pos=new Vec3(i%Width,Math.floor(i/Width),-1);
540                        MyRndGen.Seed(cast(WorldPos.x+pos.x+WorldPos.y+pos.y*139,Int));
541                        var inside:Bool=false;
542                        for (c in circles)
543                        {
544                                if (c.Inside(pos)) pos.z=0;
545                        }
546
547                        Objs[i].LogicalPos=pos;
548                        Objs[i].UpdateTex(MyRndGen);
549            Objs[i].Update(0,this);
550                }
551
552        ClearPlants();         
553        }
554
555        public function AddServerPlant(pos:Vec3,type)
556        {       
557        if (MyName!=null && SpaceClear(pos))
558        {
559            var size=MyRndGen.RndFlt()+0.5;
560            Server.Request("make-plant/"+Std.string(cast(WorldPos.x,Int))+"/"+
561                                         Std.string(cast(WorldPos.y,Int))+"/"+
562                                         Std.string(cast(pos.x,Int))+"/"+
563                                         Std.string(cast(pos.y,Int))+"/"+
564                                         type+"/"+
565                                         MyName+"/"+
566                                         Math.round(size*100),
567            this, function (c,data) {});       
568        }
569        }
570
571    public function ClearPlants() : Void
572    {
573        for (plant in Plants)
574        {
575            Remove(plant);
576        }
577        Plants = [];
578        }
579       
580        public function GetCube(pos:Vec3) : Cube
581        {
582                return Objs[cast(pos.x+pos.y*Width,Int)];
583        }
584               
585    public function SpaceClear(pos:Vec3)
586    {
587        for (plant in Plants)
588        {
589            if (plant.LogicalPos.Eq(pos)) return false;
590        }
591        return true;
592    }
593       
594        override public function Handle(e:Int)
595        {
596        super.Handle(e);
597        Update(0);
598        }
599
600    public function UpdateGhosts(c,t:Dynamic)
601    {
602        for(i in 0...t.length)
603        {
604            for (g in Spirits)
605            {
606                if (g.Name==t[i].name)
607                {
608                    g.UpdateEmotions(t[i],this);
609                }
610            }
611        }
612    }
613
614    override function Update(time:Int)
615    {
616        super.Update(time);
617
618        Server.Update();
619        TheCritters.Update();
620       
621        if (time>TickTime)
622        {
623            UpdateSpiritSprites();
624           
625            Server.Request("spirit-info",this,UpdateGhosts);
626
627            Server.Request("get-tile/"+Std.string(cast(WorldPos.x,Int))+"/"
628            +Std.string(cast(WorldPos.y,Int)),
629            this,
630            function (c:truffle.World,d)
631            {
632                var data:Array<Dynamic>=cast(d.entities,Array<Dynamic>);
633                for (p in data)
634                {
635                    var worldpos = new Vec2(p.pos.x,p.pos.y);
636                    var e = c.Get("Plant",worldpos);
637                    if (e==null)
638                    {
639                        //trace("making new plant");
640                        var cube = c.Get("Cube",worldpos);
641                        if (cube!=null)
642                        {
643                            var pos = new Vec3(p.pos.x,p.pos.y,cube.LogicalPos.z+1);   
644                            var plant = new Plant(c,p.owner,pos,p.type,p.state);
645                            c.Plants.push(plant);
646                        }
647                    }
648                    else
649                    {
650                        //trace("updating plant");
651                        //trace(e);
652                        //trace(p.state);
653                        cast(e,Plant).StateUpdate(p.state,c);
654                    }
655                }
656                c.SortScene();
657            });           
658           
659            TickTime=time+100;
660        }
661    }
662
663}
664
665//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
666
667class Fungi extends App
668{
669    public function new()
670        {
671//        Log.setColor(0xFFFFFF);
672        super(new FungiWorld(15,15));
673    }
674       
675    static function main()
676        {
677        var m:Fungi = new Fungi();
678    }
679}
Note: See TracBrowser for help on using the repository browser.